博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Delegate,Action,Func,匿名方法,匿名委托,事件
阅读量:5830 次
发布时间:2019-06-18

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

一、委托Delegate

一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如

 

[c-sharp] 
 
  1. public void HelloWorld()   
  2. {  
  3.     Console.WriteLine("Hello World!");  
  4. }  
  5. public void HelloWorld(string name)   
  6. {  
  7.     Console.WriteLine("Hello ,{0}!", name);  
  8. }  

 

但是有些时候,我们希望把一个方法本身当做参数传递给另一个方法,比如

myObject.callMethod(HelloWorld);

在没有委托之前,这是一件极困难的事情,委托出现以后,这就是一件很容易的事情了,简单点讲:委托就是一种能把方法当做参数来使用的类型--当然这个定义跟官方的解释比起来极不严密,但易于理解

要点:

1.委托是一种类型(跟string,int,double...一样是.net的一种基本类型)
2.委托的定义必须与最终被调用的方法保持签名一致

比如:下面代码中的

delegate void D1(); 与 static void HelloWorld1(),我们抛开前面的类型关键字delegate与static,他们的签名都是void X()

void D2(string myName);与void HelloWorld2(string name); void HelloWorld3(string name);它们的签名格式都是 void X(string Y)

3.委托的好处之一在于可以保持签名格式不变的情况下,动态调用不同的处理逻辑(即不同的方法)

想想系统控件中的Button类,系统并不知道按钮按下去时到底会执行怎么样的逻辑(点击后的处理,每个项目可能都不一样,完全由需求决定),但是我们知道每个Button都有一个Click(object sender, EventArgs e)这样的东东,没错,就是委托(当然封装成了另一种衍生类型event),就是这种设计保证了统一的格式,不管你实际开发中想如何处理点击后的逻辑,只要按这个统一的签名来就行了

完整代码演示:

[c-sharp] 
 
  1. using System;  
  2. namespace ActionStudy  
  3. {  
  4.     class Program  
  5.     {  
  6.          
  7.         delegate void D1();  
  8.         delegate void D2(string myName);  
  9.   
  10.   
  11.         static void Main(string[] args)  
  12.         {  
  13.             D1 d1 = new D1(HelloWorld1);  
  14.             d1();  
  15.   
  16.             D2 d2 = new D2(HelloWorld2);  
  17.             d2("Jimmy");  
  18.   
  19.             d2 = new D2(HelloWorld3);  
  20.             d2("杨俊明");              
  21.   
  22.             Console.Read();  
  23.   
  24.         }  
  25.   
  26.         static void HelloWorld1()  
  27.         {  
  28.             Console.WriteLine("Hello World!");  
  29.         }  
  30.   
  31.   
  32.         static void HelloWorld2(string name)   
  33.         {  
  34.             Console.WriteLine("Hello,{0}!", name);  
  35.         }  
  36.   
  37.         static void HelloWorld3(string name)  
  38.         {  
  39.             Console.WriteLine("你好,{0}!", name);  
  40.         }  
  41.     }  
  42. }  

 二 、匿名方法(.net2.0开始支持)

在“一、委托Delegate”的演示代码中,我们看到委托调用方法前,至少得先定义一个签名相同的方法,然后才能由委托调用(哪怕是只有一行代码的方法),好象有点烦哦,想偷懒,ok,没问题

 

[c-sharp] 
 
  1. using System;  
  2. namespace ActionStudy  
  3. {  
  4.     class Program  
  5.     {  
  6.   
  7.         delegate void D1();  
  8.         delegate void D2(string myName);  
  9.   
  10.   
  11.         static void Main(string[] args)  
  12.         {  
  13.             D1 d1 = delegate  
  14.             {  
  15.                 Console.WriteLine("Hello World!");  
  16.             };  
  17.             d1();  
  18.   
  19.             D2 d2 = delegate(string name)  
  20.             {  
  21.                 Console.WriteLine("Hello,{0}!", name);  
  22.             };  
  23.   
  24.             d2("Jimmy");  
  25.   
  26.   
  27.             d2 = delegate(string name)  
  28.             {  
  29.                 Console.WriteLine("你好,{0}!", name);  
  30.             };  
  31.   
  32.             d2("杨俊明");  
  33.   
  34.             Console.Read();  
  35.   
  36.         }  
  37.     }  
  38. }  

 

运行效果完全相同,只是省去了方法的单独定义部分

到了.net 3.0这种偷懒的作风更夸张,看下面的代码(利用了Lambda表达式)

 

[c-sharp] 
 
  1. using System;  
  2. namespace ActionStudy  
  3. {  
  4.     class Program  
  5.     {  
  6.   
  7.         delegate void D1();  
  8.         delegate void D2(string myName);  
  9.   
  10.   
  11.         static void Main(string[] args)  
  12.         {             
  13.   
  14.             D1 d1 = () => { Console.WriteLine("Hello World!"); };  
  15.             d1();  
  16.   
  17.             D2 d2 = (string name) => { Console.WriteLine("Hello,{0}!", name); };  
  18.             d2("Jimmy");  
  19.   
  20.             d2 = (string name) => { Console.WriteLine("你好,{0}!", name); };  
  21.             d2("杨俊明");  
  22.   
  23.             Console.Read();  
  24.   
  25.         }  
  26.     }  
  27. }  

 

运行效果仍然没变,初次接触者可能感觉很怪,其实我也觉得怪,不过很多大牛们都喜欢这样用,所以至少还是要能看得懂,否则别人会说"你 Out了" :)

三、Action

Action的本质就是委托,看它的定义:

[c-sharp] 
 
  1. namespace System  
  2. {  
  3.     // 摘要:  
  4.     //     Encapsulates a method that takes no parameters and does not return a value.  
  5.     public delegate void Action();  
  6. }  
  7.   
  8. namespace System  
  9. {  
  10.     // 摘要:  
  11.     //     Encapsulates a method that takes a single parameter and does not return a  
  12.     //     value.  
  13.     //  
  14.     // 参数:  
  15.     //   obj:  
  16.     //     The parameter of the method that this delegate encapsulates.  
  17.     //  
  18.     // 类型参数:  
  19.     //   T:  
  20.     //     The type of the parameter of the method that this delegate encapsulates.  
  21.     public delegate void Action<T>(T obj);  
  22. }  

 当然,还有Action<T1,T2>乃至Action<T1,T2,T3,T4>参数个数从2到4的类型,不过定义都差不多

简单点讲,Action是参数从0到4,返回类型为void(即没有返回值)的委托

 

[c-sharp] 
 
  1. using System;  
  2. namespace ActionStudy  
  3. {  
  4.     class Program  
  5.     {  
  6.         static Action A1;  
  7.         static Action<string> A2;  
  8.          
  9.         static void Main(string[] args)  
  10.         {  
  11.             A1 = new Action(HelloWorld1);  
  12.             A1();  
  13.   
  14.             A2 = new Action<string>(HelloWorld2);  
  15.             A2("Jimmy");  
  16.   
  17.             A2 = (string name) => { Console.WriteLine("你好,{0}!", name); };  
  18.             A2("杨俊明");  
  19.   
  20.             A2 = delegate(string name) { Console.WriteLine("我就是委托,{0} 你说对吗?", name); };  
  21.             A2("菩提树下的杨过");            
  22.   
  23.             Console.Read();  
  24.   
  25.         }  
  26.   
  27.         static void HelloWorld1()  
  28.         {  
  29.             Console.WriteLine("Hello World!");  
  30.         }  
  31.   
  32.         static void HelloWorld2(string name)  
  33.         {  
  34.             Console.WriteLine("Hello,{0}!", name);  
  35.         }    
  36.     }  
  37. }  

 

四、Func

Func其实也是一个"托"儿,呵呵,不过这个委托是有返回值的。看下定义就知道了:

[c-sharp] 
 
  1. namespace System  
  2. {  
  3.     // 摘要:  
  4.     //     Encapsulates a method that has no parameters and returns a value of the type  
  5.     //     specified by the TResult parameter.  
  6.     //  
  7.     // 类型参数:  
  8.     //   TResult:  
  9.     //     The type of the return value of the method that this delegate encapsulates.  
  10.     //  
  11.     // 返回结果:  
  12.     //     The return value of the method that this delegate encapsulates.  
  13.     public delegate TResult Func<TResult>();  
  14. }  
  15.   
  16. namespace System  
  17. {  
  18.     // 摘要:  
  19.     //     Encapsulates a method that has one parameter and returns a value of the type  
  20.     //     specified by the TResult parameter.  
  21.     //  
  22.     // 参数:  
  23.     //   arg:  
  24.     //     The parameter of the method that this delegate encapsulates.  
  25.     //  
  26.     // 类型参数:  
  27.     //   T:  
  28.     //     The type of the parameter of the method that this delegate encapsulates.  
  29.     //  
  30.     //   TResult:  
  31.     //     The type of the return value of the method that this delegate encapsulates.  
  32.     //  
  33.     // 返回结果:  
  34.     //     The return value of the method that this delegate encapsulates.  
  35.     public delegate TResult Func<T, TResult>(T arg);  
  36. }  

同Action类似,Func的参数从1到5个,有5个不同的重载版本

代码:

[c-sharp] 
 
  1. using System;  
  2. namespace ActionStudy  
  3. {  
  4.     class Program  
  5.     {  
  6.                   
  7.         static Func<string> F;  
  8.         static Func<DateTime, string> F2;        
  9.   
  10.   
  11.         static void Main(string[] args)  
  12.         {  
  13.             F = new Func<string>(HelloWorld1);  
  14.             Console.WriteLine(F());  
  15.   
  16.             F2 = new Func<DateTime, string>(HelloWorld2);  
  17.             Console.WriteLine(F2(DateTime.Now));  
  18.   
  19.             Console.Read();  
  20.   
  21.         }  
  22.   
  23.   
  24.         static string HelloWorld1()  
  25.         {  
  26.             return "Hello World!";  
  27.         }  
  28.   
  29.   
  30.         static string HelloWorld2(DateTime time)  
  31.         {  
  32.             return string.Format("Hello World,the time is {0}.", time);  
  33.         }  
  34.          
  35.     }     
  36. }  

五、匿名委托

ok,如果你没有晕的话,再来看一下匿名委托,其实这也是一种偷懒的小伎俩而已

看代码说话:

//F = new Func<string>(HelloWorld1);

其实也可以简写成这样:

F = HelloWorld1;          

//F2 = new Func<DateTime, string>(HelloWorld2);

其实也可以简写成这样

F2 = HelloWorld2;

方法直接赋值给委托,这二个类型不同吧???

没错,你会发现编译一样能通过,系统在编译时在背后自动帮我们加上了类似 “= new Func<...>”的东东,所以我们能偷懒一下下,这个就是匿名委托。

如果你细心的话,会发现我们在定义Button的Click处理事件时,通常是这样的:

this.button1.Click += new EventHandler(button1_Click);

但有时候我们也可以写成这样:

this.button1.Click += button1_Click;

这其实就是匿名委托的应用. 

六、事件event

其实,这...还是个托儿!

我们来看下按钮Click事件的定义

 

[c-sharp] 
 
  1. // 摘要:  
  2. //     Occurs when the control is clicked.  
  3. public event EventHandler Click;  

 

继续刨根问底,查看EventHandler的定义: 

[c-sharp] 
 
  1. using System.Runtime.InteropServices;  
  2.   
  3. namespace System  
  4. {  
  5.     // 摘要:  
  6.     //     Represents the method that will handle an event that has no event data.  
  7.     //  
  8.     // 参数:  
  9.     //   sender:  
  10.     //     The source of the event.  
  11.     //  
  12.     //   e:  
  13.     //     An System.EventArgs that contains no event data.  
  14.     [Serializable]  
  15.     [ComVisible(true)]  
  16.     public delegate void EventHandler(object sender, EventArgs e);  
  17. }  

 

看到了吧,就是委托!

 

 

来自菩提树下的杨过

 

我们在使用委托的过程中,除了为每个参数和返回类型定义一个委托之外,也就是说为每一个方法(作为参数的方法)定义一个委托,我们还可以使用Action<T>和Func<T>委托。

  泛型Action<T>委托表示引用一个void返回类型的方法。Action<T>委托类存在不同的变体,可以传递至多16种不同的参数类型,没有泛型参数的Action类可以调用没有参数的方法。例如:Action<in T1>调用带一个参数的方法,Action<in T1,in T2>调用带两个参数的方法等

  Func<T>的用法和Action<T>用法类似,但是Func<T>表示引用一个带返回类型的方法,Func<T>也存在不同的变体,至多可以传递16个参数类型和1个返回类型,例如:Func<in T1,out Resout>表示带一个参数的方法,Func<in T1,in T2,out Resout>表示调用带两个参数的方法。

  下面就直接给一个Action<T>和Func<T>的例子

using System;namespace DelegateFuncAction{    class Program    {        static void Main(string[] args)        {            Func
DoAddtion = calculate.addtion; double result = DoAddtion(20, 30); Console.WriteLine("Func带返回参数委托做加法结果为:{0}",DoAddtion(10,20)); calculate c=new calculate(); Action
DoSubstraction = c.substraction; DoSubstraction(90, 20); } } class calculate { public static double addtion(double x, double y) { return x + y; } public void substraction(double x, double y) { Console.WriteLine("Action不带返回参数委托做减法结果为:{0}",x-y); } }}

输出结果:

Func带返回参数做加法结果为:30
Action不带返回参数委托做减法结果为:70

转载于:https://www.cnblogs.com/zhangchenliang/archive/2013/05/23/3094432.html

你可能感兴趣的文章
采用JXL包进行EXCEL数据写入操作
查看>>
一周总结
查看>>
将txt文件转化为json进行操作
查看>>
线性表4 - 数据结构和算法09
查看>>
uva-317-找规律
查看>>
我的2014-相对奢侈的生活
查看>>
Java设计模式
查看>>
Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin
查看>>
ORM数据库框架 SQLite 常用数据库框架比较 MD
查看>>
华为OJ 名字美丽度
查看>>
微信公众号与APP微信第三方登录账号打通
查看>>
onchange()事件的应用
查看>>
Windows 下最佳的 C++ 开发的 IDE 是什么?
查看>>
软件工程师成长为架构师必备的十项技能
查看>>
python 异常
查看>>
百度账号注销
查看>>
mysql-This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME 错误解决
查看>>
BIEE Demo(RPD创建 + 分析 +仪表盘 )
查看>>
Cocos2dx 3.0开发环境的搭建--Eclipse建立在Android工程
查看>>
基本概念复习
查看>>