博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
转载 C#匿名函数 委托和Lambda表达式
阅读量:5136 次
发布时间:2019-06-13

本文共 5008 字,大约阅读时间需要 16 分钟。

转载原出处: http://blog.csdn.net/honantic/article/details/46331875

匿名函数

  匿名函数(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.委托的调用列表(多播委托) 
  委托实例所封装的方法集合称为调用列表。 
  当我们从某个方法创建一个委托实例的时候,该实例将封装此方法,该实例中的调用列表包含一个“入口点”。当我们组合多个非空的委托实例的时候,它们的调用列表将连接在一起形成一个新的调用列表,新的调用列表中包含了多个“入口点”。 
  委托的组合是使用二元运算符 + 和 += 来进行的,同样可以使用 - 和 -= 来进行组合的移除。 
   
  下面的示例演示多个委托的实例化及其相应的调用列表:

      

1 delegate void D(int x) 2 class 3 { 4     public static void M1(int i){...} 5     public static void M2(int i){...} 6 } 7 class Test 8 { 9     static void Main()10     {11         D cd1 = new D(c.M1);            //M112         D cd2 = new D(c.M2);            //M213         D cd3 = cd1 + cd2;              //M1 + M214         D cd4 = cd3 + cd1;              //M1 + M2 + M115         D cd5 = cd4 + cd3;              //M1 + M2 + M1 + M216     }17 }

 实例化cd1和cd2的时候,它们分别封装一个方。实例化cd3的时候,它调用的列表有两个方法M1和M2,而且顺序与此相同。cd4的调用列表中依次包含M1、M2、M1。最后,cd5的调用列表中依次包含M2、M1、M1、M2。 

4.委托的调用 

当调用一个委托实例的时候,将按照调用列表的顺序依次调用列表中的各个方法,当在调用期间发生异常,调用列表中排在后面的任何方法将不会被调用。

 

1 using System; 2 delegate void D(int x); 3 class C 4 { 5     public static void M1(int i) 6     { 7         Console.WriteLine("C.M1:"+i); 8     } 9 10     public static void M2(int i)11     {12         Console.WriteLine("C.M1:"+i);13     }  14 15     public  void M3(int i)16     {17         Console.WriteLine("C.M2:"+i);18     }19 }20 21 class Test22 {23     static void Main()24     {25         D cd1 = new D(c.M1);            //M126         cd1(-1);                        //调用cd127 28         D cd2 = new D(c.M2);            //M229         cd2(-2);                        //调用M230 31         D cd3 = cd1 + cd2;              //M1 + M232         cd3(10);                        //依次调用M1、M233 34         cd3 += cd1;35         cd3(20);                        //依次调用M1、M2、M136 37         C c = new C();38         D cd4 = new D(c.M3);            39         cd3 += cd4;40         cd3(30);                        //依次调用M1、M2、M1、M341 42         cd3 -= cd1                      //移除最后一个M143         cd3(40);                        //依次调用M1、M2、M344 45         cd3 -= cd4;                     46         cd3(50);                        //依次调用M1、M247 48         cd3 -= cd249         cd3(60);                        //调用M150 51         cd3 -= cd2                      //这是cd3的调用列表中没有cd2了,该移除不生效,不报错52         cd3(70);                        //调用M153 54         cd3 -= cd1                      55         //      cd3(70);                //如果调用,将会报System.NullReferenceException异常56     }57 }

Lambda表达式

自从3.0开始,就可以使用一种新语法把实现代码赋予委托:Lambda表达式。只要有委托参数类型的地方,就可以使用Lambda表达式。使用匿名方法的地方可以使用Lambda表达式来代替,例如:

1 Func< string,string > = delagate(string para) 2 { 3     para += "Hello World!"; 4     return param; 5 } 6 可以写成 7 Func< string,string > = para=> 8 { 9     para +="Hello World!";10     return para;11 }

Lambda表达式运算符”=>”的左边列出了需要的参数,右边定义了赋予Lambda变量的方法的代码实现。 

  我们注意到,无论何时,只要我们需要引入匿名方法,我们都需要在前面加上delegate关键字,而且参数列表都需要类型化。Lambda表达式提供了一种更为简洁和自然的语法,而且在C#更多高级的方面中都涉及广泛。简而言之,我们应该用Lambda表达式来替代匿名方法。 
  例如:

1 public class Person 2 { 3     string Name; 4     int Age; 5 } 6  7 List
personList = new List
(); 8 9 personList.Find(delegate(Person p){retrun p.Age==12;});10 //可以写成11 personList.Find(p=>p.Age==12);

 

            

 

转载于:https://www.cnblogs.com/wphl-27/p/5504353.html

你可能感兴趣的文章
nginx+uWSGI+django+virtualenv+supervisor发布web服务器
查看>>
什么是NSIS?
查看>>
从100PV到1亿级PV网站架构演变(转)
查看>>
scrapy Pipeline 练习
查看>>
Insert a Drop Down Calendar Menu In Excel – Choose a Date!
查看>>
56. Merge Intervals(js)
查看>>
MapReduce
查看>>
夜未眠1
查看>>
C++ 模板
查看>>
post参数的方法 json data 和特别的传参
查看>>
3.1本地数据获取
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第5节 final关键字_2_final关键字用于修饰类...
查看>>
lockback 生成json 日志配置
查看>>
【甲午年正月初九】测试的需求文档评审
查看>>
ASP导出数据到excel遇到的一些问题
查看>>
pdf文件之itextpdf插入html内容以及中文解决方案
查看>>
恭送功臣
查看>>
CSS清除浮动
查看>>
犯罪都市
查看>>
Android ViewPager再探:增加滑动指示条
查看>>