委托简介
什么是委托
- C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。它是一个对象,他知道该如何调用一个方法,其实它就是一个方法的包装器或引用变量。
定义委托
- 委托类型:委托类型定义了委托实例可以调用的那类方法,即定义了方法的返回类型和参数类列表
- 所有的委托类型都派生于
System.MuticastDelegate
,而它又派生于System.Delegate
- 委托实例:把方法赋值给委托变量时就创建了委托实例
1 | class Program |
委托的好处
- 委托实例其实就是调用者的委托:调用者调用委托,再由委托调用目标方法。这样做的好处就是把调用者和目标方法解耦合了,使用delegate能很容易地写出经典的设计模式。下面有一个列子:在调用者和目标函数中间加入了中间层,可以使用这个中间层对目标方法进行增强,这就是适配器设计模式(类似于插件)。
1 | class Program |
多播委托
- 一个委托实例可以引用一组目标方法,所有的委托实例都具有多播的功能。
- 使用
+
或+=
操作符就可以合并委托实例,合并后调用就会顺序地调用各个委托实例委托的方法,调用的顺序跟合并的顺序一致。 - 使用
-
或-=
操作访可以移除合并的委托实例。 - C#会把这些操作符编译成
System.Delegate
中的Combine
和Remove
两个静态方法
1 | class Program |
实例方法目标和静态方法目标
- 当一个实例方法被赋值给委托对象的时候,这个委托对象不仅要保留着对方法的引用,还要保留着方法所属实例的引用
- 而实例的引用就是
System.Delegate
中的Target
属性。 - 如果引用的是静态方法,那么
Target
属性的值就为null
1 | class Program |
泛型委托类型
- 委托类型可以包含泛型类型的参数,
public delegate T Transformer<T> (T arg);
1 | class Program |
Func和Action委托
Func
Func
类型的定义都放在了System命名空间下,它代表的是有返回值的委托类型,它有多种不同的泛型类型可供使用:delegate TResult Func<out TResult>();
:有返回值,没有参数的委托类型,out表示TResult
类型的变量只能作为方法的输出。delegate TResult Func<in T, out TResult>(T arg);
:有返回值,一个参数的委托类型,in表示T
类型的变量只能作为方法的输入。delegate TResult Func<in T1, in T2... out TResult>(T1 arg1, T2 arg2...);
:有返回值,多个个参数的委托类型,最多可以支持16个输入参数。
Action
Action
类型的定义都放在了System命名空间下,它代表的是没有返回值的委托类型,它有多种不同的泛型类型可供使用:
delegate void Action();
:没有返回值,没有参数的委托类型。delegate void Action<in T>(T arg);
:没有返回值,一个参数的委托类型。delegate void Action<in T1, in T2...>(T1 arg1, T2 arg2...);
:没有返回值,多个个参数的委托类型,最多可以支持16个输入参数。
1 | class Program |
接口和委托
- 委托可以解决的委托,接口都可以解决,那在什么时候更适合自定义的委托而不是使用接口呢?
- 需要多播的功能,接口不能实现多播的功能
- 订阅者需要多次实现接口jian
委托的兼容性
- 委托类型:委托类型之间时互不相容的,即使方法签名一样。
- 委托实例:如果委托实例拥有相同的方法目标,那么委托实例就是相等的。
- 参数:委托可以接受比它的定义参数类型更加抽象的参数类型的方法,这个叫做委托的逆变。
- 返回值:委托可以接受比它的定义返回类型更加具体的返回类型的方法,这个叫做委托的协变。
1 | class Program |
- 而委托支持的仅仅只是引用转换,而不支持装箱拆箱操作,比如下面例子:他并不支持将int进行装箱
1 | class Program |
学习资料:B站杨旭