1.委托和事件的关系
委托之于事件,相当于字段之于属性
事件本质上就是对多播委托的语法和访问级别上的封装,其主要作用是:
- 限制访问:外部代码不能直接调用事件(只能 += / -=);
- 仅允许通过 +=(订阅)和 -=(取消订阅)的方式管理回调;
- 隐藏委托对象的调用权。
2.委托/事件+=和-=的本质
委托:定义委托类型 -> 声明委托变量 -> 将委托实例赋值给委托变量
delegate void Calculate(int x, int y); // 声明委托类型
public static void add(int x, int y)
{
Console.WriteLine("add=" + (x + y));
}
public static void sub(int x, int y)
{
Console.WriteLine("sub=" + (x - y));
}
Calculate calculate; // 声明委托变量
calculate += add; // 将委托实例赋值给委托变量
calculate += sub; // 将委托实例赋值给委托变量
但实际上 += 在此处属于语法糖,本质上是:
calculate = (Calculate)Delegate.Combine(calculate, new Calculate(add));
事件:声明事件(event关键字 + 委托类型)变量 -> 将委托实例赋值给事件变量
本质同上:
SomethingHappened += new EventHandler(SomeMethod);
_somethingHappened = (EventHandler)Delegate.Combine(_somethingHappened, new EventHandler(SomeMethod));
3.传参问题
无参异步委托传入有参异步委托:
为Func<Task>形参传入Func<Task<T>>委托,可以执行,编译器会将其封装为Func<Task>,但是无法获取返回值T
同步委托传入异步委托:
无法为Func<T>传入异步委托:异步委托无论是返回void,Task或Task<T>,都不可转换为Func<T>
部分情况下可以为Action传入异步委托:异步函数返回值为void时符合条件(只是此时的异步函数是"以同步方式运行的异步函数",无意义),为Task时Task会被隐式遗弃,为Task<T>时无法编译通过(Task<T>无法隐式遗弃,而Action不接受返回值),所以当异步委托返回值为void或Task时可以将其传入给Action