委托-C#

图

委托

委托是一个对象,它知道如何调用一个方法。

委托类型 & 委托实例

委托类型定义了委托实例可以调用的那类方法,具体来说,委托类型定义了方法的返回类型和参数。

1
2
3
4
5
//Transformer这个委托,所需参数和返回类型均为 int, 与下面的方法 Square() 一致,所以该委托可调用这个方法。
delegate int Transformer(int x);

static int Square(int x) { return x*x }
static int Square(int x) => x*x; //Expression Body 形式

委托实例

  • 委托的实例 其实就是调用者的委托:调用者调用委托,然后委托调用目标方法。
  • 间接的把调用者和目标方法解耦了。

Demo1:

  • 把方法赋值给委托变量的时候就创建了委托实例。

    1
    2
    Transformer t = Square;    //简写形式
    Transformer t = new Transformer(Square); //完整形式
  • 调用

    1
    2
    int answer = t(3);    //简写形式,answer is 9
    t.invoke(3); //完整形式

在这里插入图片描述

编写插件式的方法

  • 方法是在运行时才赋值给委托变量

Demo2:
在这里插入图片描述

多播委托

所有的委托实例都具有多播的能力。一个委托实例可以引用一组目标方法

  • “+” 和 “ += ” 操作符可以合并委托实例
    1
    2
    3
    4
     SomeDelegate d = SomeMethod 1;
    d += SomeMethod2;

    d = d + SomeMethod2;
  • 调用d就会调用SomeMethod1 和 SomeMethod2
  • 委托的调用顺序与它们的定义顺序一致
  • “ - ” 和 “ -= ” 会把右边的委托从左边的委托里 移除

    1
    d -= SomeMethod1;
  • 委托变量使用 + 或 += 时,其操作数可以是 null。

  • 使用 += 或 -= 时,实际上是创建了新的委托实例,并把它赋给当前的委托变量。
  • 如果多播委托的返回类型不是 void,那么调用者从最后一个被调用的方法来接受返回值。前面的方法仍会被调用,但是其返回值被弃用了。

实例方法目标 和 静态方法目标

  • 当一个实例方法被赋值给委托对象的时候,这个委托对象不仅要保留着对方法的引用,还要保留着方法所属实例的引用。
  • System.Delegate 的 Target属性 就代表着这个实例。
    如果引用的是静态方法,那么Target属性的值就是 null。

Demo3:
委托p所调用的方法,其所属实例就是x。打印出所调用的方法名

泛型委托类型

  • 泛型委托类型可以包含泛型类型参数
    1
    public delegate T Transformer<T> (T arg);

Demo:
泛型类型T ,最后的结果可根据 values数组 自动识别出来

Func 和 Action 委托 (略过)

使用泛型委托,就可以写出这样一组委托类型,它们可调用的方法可以拥有任意的返回类型任意(合理)数量的参数

可以把上面Demo中的 Transform方法中的委托参数改为:结果也是一样的。

1
public static void Transform<T>(T[] values, Func<T, T> t)

委托 VS 接口

委托可以解决的问题,接口都可以解决。

什么情况下更适合使用委托而不是接口呢?当下列条件满足之一:

  • 接口只能定义一个方法
  • 需要多播能力
  • 订阅者需要多次实现接口

委托的兼容性 - 委托类型

  • 委托类型之间互不相容,即使 签名方法一样

    1
    2
    3
    4
    5
    delegate void  D1();
    delegate void D2();
    ...
    D1 d1 = Method1;
    D2 d2 = d1; //Compile - time error
  • 如果委托实例拥有相同的方法目标,那么委托实例就认为是相等的

    1
    2
    3
    4
    5
     delegate void D();
    ...
    D d1 = Method1;
    D d2 = Method1;
    console.WriteLine( d1 == d2); //True

委托的兼容性 - 参数

  • 当调用一个方法时,提供的参数(argument)可以比方法的参数(parameter) 定义更具体。
  • 委托可以接受比它的方法目标更具体的参数类型,这叫 ContraVariance. 逆变

委托的兼容性 - 返回类型

  • 调用方法时,可以得到一个比请求的类型更具体的类型的返回结果
  • 委托的目标方法可以返回bi委托描述里更具体的类型返回结果。Co’v’ariance 协变
坚持原创分享,您的支持将鼓励我继续创作!