一、委托Delegate
一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如
- public void HelloWorld()
- {
- Console.WriteLine("Hello World!");
- }
- public void HelloWorld(string name)
- {
- Console.WriteLine("Hello ,{0}!", name);
- }
但是有些时候,我们希望把一个方法本身当做参数传递给另一个方法,比如
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),就是这种设计保证了统一的格式,不管你实际开发中想如何处理点击后的逻辑,只要按这个统一的签名来就行了
完整代码演示:- using System;
- namespace ActionStudy
- {
- class Program
- {
- delegate void D1();
- delegate void D2(string myName);
- static void Main(string[] args)
- {
- D1 d1 = new D1(HelloWorld1);
- d1();
- D2 d2 = new D2(HelloWorld2);
- d2("Jimmy");
- d2 = new D2(HelloWorld3);
- d2("杨俊明");
- Console.Read();
- }
- static void HelloWorld1()
- {
- Console.WriteLine("Hello World!");
- }
- static void HelloWorld2(string name)
- {
- Console.WriteLine("Hello,{0}!", name);
- }
- static void HelloWorld3(string name)
- {
- Console.WriteLine("你好,{0}!", name);
- }
- }
- }
二 、匿名方法(.net2.0开始支持)
在“一、委托Delegate”的演示代码中,我们看到委托调用方法前,至少得先定义一个签名相同的方法,然后才能由委托调用(哪怕是只有一行代码的方法),好象有点烦哦,想偷懒,ok,没问题
- using System;
- namespace ActionStudy
- {
- class Program
- {
- delegate void D1();
- delegate void D2(string myName);
- static void Main(string[] args)
- {
- D1 d1 = delegate
- {
- Console.WriteLine("Hello World!");
- };
- d1();
- D2 d2 = delegate(string name)
- {
- Console.WriteLine("Hello,{0}!", name);
- };
- d2("Jimmy");
- d2 = delegate(string name)
- {
- Console.WriteLine("你好,{0}!", name);
- };
- d2("杨俊明");
- Console.Read();
- }
- }
- }
运行效果完全相同,只是省去了方法的单独定义部分
到了.net 3.0这种偷懒的作风更夸张,看下面的代码(利用了Lambda表达式)
- using System;
- namespace ActionStudy
- {
- class Program
- {
- delegate void D1();
- delegate void D2(string myName);
- static void Main(string[] args)
- {
- D1 d1 = () => { Console.WriteLine("Hello World!"); };
- d1();
- D2 d2 = (string name) => { Console.WriteLine("Hello,{0}!", name); };
- d2("Jimmy");
- d2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
- d2("杨俊明");
- Console.Read();
- }
- }
- }
运行效果仍然没变,初次接触者可能感觉很怪,其实我也觉得怪,不过很多大牛们都喜欢这样用,所以至少还是要能看得懂,否则别人会说"你 Out了" :)
三、ActionAction的本质就是委托,看它的定义:
- namespace System
- {
- // 摘要:
- // Encapsulates a method that takes no parameters and does not return a value.
- public delegate void Action();
- }
- namespace System
- {
- // 摘要:
- // Encapsulates a method that takes a single parameter and does not return a
- // value.
- //
- // 参数:
- // obj:
- // The parameter of the method that this delegate encapsulates.
- //
- // 类型参数:
- // T:
- // The type of the parameter of the method that this delegate encapsulates.
- public delegate void Action<T>(T obj);
- }
当然,还有Action<T1,T2>乃至Action<T1,T2,T3,T4>参数个数从2到4的类型,不过定义都差不多
简单点讲,Action是参数从0到4,返回类型为void(即没有返回值)的委托
- using System;
- namespace ActionStudy
- {
- class Program
- {
- static Action A1;
- static Action<string> A2;
- static void Main(string[] args)
- {
- A1 = new Action(HelloWorld1);
- A1();
- A2 = new Action<string>(HelloWorld2);
- A2("Jimmy");
- A2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
- A2("杨俊明");
- A2 = delegate(string name) { Console.WriteLine("我就是委托,{0} 你说对吗?", name); };
- A2("菩提树下的杨过");
- Console.Read();
- }
- static void HelloWorld1()
- {
- Console.WriteLine("Hello World!");
- }
- static void HelloWorld2(string name)
- {
- Console.WriteLine("Hello,{0}!", name);
- }
- }
- }
四、Func
Func其实也是一个"托"儿,呵呵,不过这个委托是有返回值的。看下定义就知道了:
- namespace System
- {
- // 摘要:
- // Encapsulates a method that has no parameters and returns a value of the type
- // specified by the TResult parameter.
- //
- // 类型参数:
- // TResult:
- // The type of the return value of the method that this delegate encapsulates.
- //
- // 返回结果:
- // The return value of the method that this delegate encapsulates.
- public delegate TResult Func<TResult>();
- }
- namespace System
- {
- // 摘要:
- // Encapsulates a method that has one parameter and returns a value of the type
- // specified by the TResult parameter.
- //
- // 参数:
- // arg:
- // The parameter of the method that this delegate encapsulates.
- //
- // 类型参数:
- // T:
- // The type of the parameter of the method that this delegate encapsulates.
- //
- // TResult:
- // The type of the return value of the method that this delegate encapsulates.
- //
- // 返回结果:
- // The return value of the method that this delegate encapsulates.
- public delegate TResult Func<T, TResult>(T arg);
- }
同Action类似,Func的参数从1到5个,有5个不同的重载版本
代码:- using System;
- namespace ActionStudy
- {
- class Program
- {
- static Func<string> F;
- static Func<DateTime, string> F2;
- static void Main(string[] args)
- {
- F = new Func<string>(HelloWorld1);
- Console.WriteLine(F());
- F2 = new Func<DateTime, string>(HelloWorld2);
- Console.WriteLine(F2(DateTime.Now));
- Console.Read();
- }
- static string HelloWorld1()
- {
- return "Hello World!";
- }
- static string HelloWorld2(DateTime time)
- {
- return string.Format("Hello World,the time is {0}.", time);
- }
- }
- }
五、匿名委托
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事件的定义
- // 摘要:
- // Occurs when the control is clicked.
- public event EventHandler Click;
继续刨根问底,查看EventHandler的定义:
- using System.Runtime.InteropServices;
- namespace System
- {
- // 摘要:
- // Represents the method that will handle an event that has no event data.
- //
- // 参数:
- // sender:
- // The source of the event.
- //
- // e:
- // An System.EventArgs that contains no event data.
- [Serializable]
- [ComVisible(true)]
- public delegate void EventHandler(object sender, EventArgs e);
- }
看到了吧,就是委托!
来自菩提树下的杨过
我们在使用委托的过程中,除了为每个参数和返回类型定义一个委托之外,也就是说为每一个方法(作为参数的方法)定义一个委托,我们还可以使用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) { FuncDoAddtion = 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 |