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、为泛型类型参数指定逆变
不是太明白。。。。。。