当前位置:首页 > Windows程序 > 正文

[深入学习C#]匿名函数、委托和Lambda表达式

2021-05-26 Windows程序

  匿名函数(Anonymous Function)是表示“内联”方法定义的表达式。匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型。匿名函数转换的计算取决于转换的目标类型:如果是委托类型,则转换计算为引用匿名函数所定义的方法的委托;如果是表达式树类型,则转换将计算以对象结构形式表示方法结构的表达式树。
  匿名函数有两种语法风格:Lambda表达式(lambda-expression)和匿名方法表达式(anonymous-method-expression)。在几乎所有的情况下,Lambda表达式都比匿名方法表达式更为简介具有表现力。但现在C#语言中仍保留了后者,为了向后兼容。
  Lambda表达式:
    async可选 (匿名的函数签名)=> (匿名的函数体)
  匿名方法表达式:
    async可选 delegate (显式的匿名函数签名) 可选{代码块}

  其中匿名的函数签名可以包括两种,一种是隐式的匿名函数签名另一种是显式的匿名函数签名:
    隐式的函数签名:(p)、(p1,p1)
    显式的函数签名:(int p)、(int p1,int p2)、(ref int p1,out int p2)
  匿名的函数体可以是表达式或者代码块。

  从上面我们可以看出,Lambda表达式的参数形式可以显式或者隐式类型化。在显式类型化参数列表中,每个参数的类型是显式声明的,在隐式类型化参数列表中,参数的类型是从匿名函数出现的上下文中推断出来的。
  当Lambda表达式只有一个具有隐式类型化参数的时候,参数列表可以省略圆括号,也就是说:
  (参数) => 表达式
  可以简写为
  参数 => 表达式

一些匿名函数的示例
  x => x + 1 //隐式的类型化,函数体为表达式
  x => {return x + 1;} //隐式的类型化,函数体为代码块
  (int x) => x + 1 //显式的类型化,函数体为表达式
  (int x) => {return x + 1;} //显式的类型化,函数体为代码块
  (x , y) => x * y //多参数
  () => Console.WriteLine() //无参数
  async (t1 , t2) => await t1 + await t2 //异步
  delegate (int x) {return x + 1;} //匿名函数方法表达式
  delegate {return 1 + 1;} //参数列表省略
  
Lambda表达式和匿名方法表达式的区别:
  ● 当没有参数的时候,匿名方法表达式允许完全省略参数列表,从而可以转换为具有任意值参数列表的委托类型,Lambda表达式则不能省略参数列表的圆括号()。
  ● Lambda表达式允许省略和推断类型参数,而匿名方法表达式要求显式声明参数类型。
  ● Lambda表达式主体可以为表达式或者代码块,而匿名方法表达式的主体必须为代码块。
  ● 只有Lambda表达式可以兼容到表达式树类型。

委托

  一个委托是一个指向一个方法的引用,或者说,一个委托的实例就是一个指向某个方法的对象,这是一个简单却十分强大的概念。
  C#中的委托是用来处理在其他语言中(如C++、Pascal等)需要用函数指针来处理的情况。不过与C++不同的是:委托是完全面向对象的;C++指针仅仅指向成员函数,而委托同时封装了对象的实例和方法;委托是完全类型安全的,只有当函数的签名与委托的签名匹配的时候,委托才可以指向该方法,当委托没有合法的指向方法的时候不能被调用。

  一些关于委托的知识点:
  
  1.委托是类型安全的
  委托类型的返回类型必须为void或者输出安全,,委托类型的所有形参类型都必须是输入安全的。
  
  2.委托类型是名称等效,不是结构等效
  也就是说,对于两个委托类型,即使它们具有相同的参数列表和返回类型,它们仍将被视为两个不同的委托类型。
  例如:
  delegate int A(int x);
  delegate int B(int x);
  A和B是两个不同的委托。
  
  但是,两个结构一样的委托,它们的实例可以指向同一个方法。
  
  3.委托的调用列表(多播委托)
  委托实例所封装的方法集合称为调用列表。
  当我们从某个方法创建一个委托实例的时候,该实例将封装此方法,该实例中的调用列表包含一个“入口点”。当我们组合多个非空的委托实例的时候,它们的调用列表将连接在一起形成一个新的调用列表,新的调用列表中包含了多个“入口点”。
  委托的组合是使用二元运算符 + 和 += 来进行的,同样可以使用 - 和 -= 来进行组合的移除。
  
  下面的示例演示多个委托的实例化及其相应的调用列表:

delegate void D(int x) class { public static void M1(int i){...} public static void M2(int i){...} } class Test { static void Main() { D cd1 = new D(c.M1); //M1 D cd2 = new D(c.M2); //M2 D cd3 = cd1 + cd2; //M1 + M2 D cd4 = cd3 + cd1; //M1 + M2 + M1 D cd5 = cd4 + cd3; //M1 + M2 + M1 + M2 } }

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/71396.html