【读书笔记】编写高质量代码改善C# 建议39- 45(⭐委托实质)

39、了解委托的实质

委托是方法指针,显而易见

委托是一个类,我们自己新建的委托编译成IL代码后就是一个类,系统定义的Action Func也是一个类

不同的是,系统定义的委托不论你用几个对象 Action<int>  Action<String>  Func<int,string> 都是存储在一个类里面

所以之前有建议,尽量使用系统预定义的委托和事件不无道理,下面看一下IL代码

这是C#代码

这是编译出来的IL代码

明显图中看到MyDelegate委托生成了一个类,此类继承自MulticastDelegate多播委托,除了构造方法还有三个Invoke

而我们使用了两个Action 一个Func 他们都在一个类里面生成

下面看看委托的添加和调用

  IL_0000:  nop
  IL_0001:  newobj     instance void CSharpSuggest.Task::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldftn      instance void CSharpSuggest.Task::Run()
  IL_000e:  newobj     instance void CSharpSuggest.MyDelegate::.ctor(object,
                                                                     native int)
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  ldloc.0
  IL_0016:  ldftn      instance void CSharpSuggest.Task::Run2()
  IL_001c:  newobj     instance void CSharpSuggest.MyDelegate::.ctor(object,
                                                                     native int)
  IL_0021:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                          class [mscorlib]System.Delegate)
  IL_0026:  castclass  CSharpSuggest.MyDelegate
  IL_002b:  stloc.1
  IL_002c:  ldloc.1
  IL_002d:  callvirt   instance void CSharpSuggest.MyDelegate::Invoke()

IL_001c:生成了一个MyDelegate的实例

IL_0021:调用Delegate.Combine方法,将两个委托组合到一起

 IL_002d:调用MyDelegate里面的Invoke方法

40、使用event关键字为委托添加保护

委托如果是不允许除了发布者之外的任何人调用的,尽量使用事件来添加保护

41、实现标准的事件模型

/// <summary>
/// 传递的参数 继承EventArgs
/// </summary>
class FileUploadedEventArgs : EventArgs
{
    public int FileProgress { get; set; }
}

/// <summary>
/// 事件类型  =  EventHandler<参数类型>
/// </summary>
public event EventHandler<FileUploadedEventArgs> FileUploaded;

还是那样 注意使用系统自带的事件类型

42、使用泛型参数兼容泛型接口的不可变性

如果是一个泛型接口作为另外一个方法的参数,我们最好也在该方法使用泛型来兼容接口的不同类型

static void PrintSalart<T>(ISalary<T> s)
{
    s.Pay();
}

43、让接口中的泛型参数支持协变

什么是协变呢, 意思的  和谐的变化 如果Teacher继承自Person 从Teacher变到Peroson就是协变

还有逆变 就是不正常的变化 从Person变到Teacher就是逆变

形参是ISalary<Person>  形参可以传入ISalary<Teacher>  Teacher继承自Person

interface ISalary<out T>
{
    void Pay();
}

这样加个out就支持了

44、理解委托中的协变

如果在委托中使用了泛型,务必都使用 out 参数,将会拓展该委托的应用

实际测试发现书上的例子并不会报错。。

45、为泛型类型参数指定逆变

不是太明白。。。。。。

猜你喜欢

转载自blog.csdn.net/qq_33413868/article/details/81483735