C# 委托(Delegate)

什么是委托

委托跟类一样,是用户自定义的类型。但类是表示数据的集合,委托是具有兼容返回类型和输入参数的方法或lambda表达式的集合。
如果你学过C++,那么可以把委托理解为指向函数的指针。但是,委托是类型安全和可靠的。
你可以把委托看做一个包含有【有序方法列表】的对象。这些方法具有相同的返回类型和签名(参数列表,包括ref和out修饰符)。
在调用委托时,会执行【有序方法列表】的所有方法。

委托的使用
  • 声明委托类型
delegate <return type> <delegate-name> <parameter list>
e.g.
delegate void Mydel(int x);
  • 创建委托对象
//变量声明
Mydel delVaer;

//使用带new运算符的对象创建表达式
delVar = new MyDel(Method1);
//快捷语法
delVar = Method1;

//当然也可以把创建变量初始化放在一起
Mydel delVar = new MyDel(Method1);
Mydel delVar = Method1;
**委托是引用类型**
  • 组合委托
MyDel delA = Method1;
MyDel delB = Mythod2;
MyDel delC = delA + delB;
//delC的方法列表是delA和delB的方法列表的组合
  • 为委托增加方法
Mydel del = Method1;
del += Method2;
del += Method3;
//委托是不可变的,所以实际发生的是创建了一个新委托,其调用列表是旧委托列表和方法的组合,然后这个新的委托赋值给del
  • 从委托移除方法
del  -=  Method1;
//和增加方法一样,这里实际发生的是创建了一个新的委托

需要注意的是:
1. 删除的过程是从列表的最后开始搜索,并且移除第一个匹配的放法。
2. 试图删除委托中不存在的放法没有效果
3. 试图调用空委托会发生异常
4. 如果委托的调用列表为空,则委托是null

  • 调用委托
    可以像调用方法一样调用委托,委托的参数会用于方法列表的所有方法(除非有一个参数是输出参数)。
Mydel del = Method1;
del += Method2;
del += Method3;
del();//调用委托
  • 调用带返回参数的委托
    如果委托有返回值并且在调用列表中有一个以上的方法,会发生下面的情况:

    1. 调用列表最后一个方法的返回值就是委托的返回值
    2. 调用列表中其他方法的返回值都会被忽略
  • 调用带引用参数的委托

  • 匿名方法

delegate int Mydel(int x);
Mydel del = delegate (int x){return x+1;}

emmm,就是没有名字的方法。
语法:

delegate (Parameters){ ImplementationCode }
  1. 返回类型:匿名方法不会显式的声明返回类型,但其返回类型必须与对应的委托相一致
  2. 参数:必须与委托一致。需要注意的是,委托中的params关键字会被匿名方法忽略。
  3. 被捕获变量的生命周期会拓展。
delegate void Mydel();
static void Main(){
  Mydel del;
  {
    int x = 5;//对匿名函数而言是外部变量
    del = delegate(){
      Console.WriteLine(x);//x被捕获
    }
  }
  Console.WriteLine(x);//报错,未定义x
  if (del != null){
    del();//输出x的值
  }
}
  • Lamabda表达式
    emmm,跟匿名函数一样是为了方便。其实,如果lambda表达式如果被先引进,就不会有匿名函数了。
Mydel del = delegate(int x)  {return x+1;}
Mydel del =         (int x)=>{return x+1;}
Mydel del =         (x)=>{return x+1}//可以省略类型
Mydel del =         x =>{return x+1}//如果只有一个参数可以省略()
Mydel del = x => x+1//若果语句块只包含一个返回语句,则可以把语句块替换为return后的表达式

lambda表达式要点:
1. lambda表达式参数列表中的参数必须在类型、数量和位置上与委托相匹配
2. 参数类型可以省略(隐式类型)。除非委托中有ref或者out参数—此时类型是必须的。
3. 如果只有一个参数并且是隐式的,则可以省略(),否则()是必须的
4. 如果没有参数,必须使用()

猜你喜欢

转载自blog.csdn.net/guojunxiu/article/details/81010849