Delegate,Action,Func,匿名方法,匿名委托,事件

一、委托Delegate

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


public void HelloWorld()
{
Console.WriteLine(
" HelloWorld! " );
}
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)
{
D1d1
= new D1(HelloWorld1);
d1();

D2d2
= new D2(HelloWorld2);
d2(
" Jimmy " );

d2
= new D2(HelloWorld3);
d2(
" 杨俊明 " );

Console.Read();

}

static void HelloWorld1()
{
Console.WriteLine(
" HelloWorld! " );
}


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)
{
D1d1
= delegate
{
Console.WriteLine(
" HelloWorld! " );
};
d1();

D2d2
= 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)
{

D1d1
= () => {Console.WriteLine( " HelloWorld! " );};
d1();

D2d2
= ( string name) => {Console.WriteLine( " Hello,{0}! " ,name);};
d2(
" Jimmy " );

d2
= ( string name) => {Console.WriteLine( " 你好,{0}! " ,name);};
d2(
" 杨俊明 " );

Console.Read();

}
}
}

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

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


namespace System
{
// 摘要:
// Encapsulatesamethodthattakesnoparametersanddoesnotreturnavalue.
public delegate void Action();
}

namespace System
{
// 摘要:
// Encapsulatesamethodthattakesasingleparameteranddoesnotreturna
// value.
//
// 参数:
// obj:
// Theparameterofthemethodthatthisdelegateencapsulates.
//
// 类型参数:
// T:
// Thetypeoftheparameterofthemethodthatthisdelegateencapsulates.
public delegate void Action < T > (Tobj);
}

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

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


using System;
namespace ActionStudy
{
class Program
{

static ActionA1;
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(
" HelloWorld! " );
}


static void HelloWorld2( string name)
{
Console.WriteLine(
" Hello,{0}! " ,name);
}


}



}

四、Func

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


namespace System
{
// 摘要:
// Encapsulatesamethodthathasnoparametersandreturnsavalueofthetype
// specifiedbytheTResultparameter.
//
// 类型参数:
// TResult:
// Thetypeofthereturnvalueofthemethodthatthisdelegateencapsulates.
//
// 返回结果:
// Thereturnvalueofthemethodthatthisdelegateencapsulates.
public delegate TResultFunc < TResult > ();
}

namespace System
{
// 摘要:
// Encapsulatesamethodthathasoneparameterandreturnsavalueofthetype
// specifiedbytheTResultparameter.
//
// 参数:
// arg:
// Theparameterofthemethodthatthisdelegateencapsulates.
//
// 类型参数:
// T:
// Thetypeoftheparameterofthemethodthatthisdelegateencapsulates.
//
// TResult:
// Thetypeofthereturnvalueofthemethodthatthisdelegateencapsulates.
//
// 返回结果:
// Thereturnvalueofthemethodthatthisdelegateencapsulates.
public delegate TResultFunc < T,TResult > (Targ);
}

同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 " HelloWorld! " ;
}


static string HelloWorld2(DateTimetime)
{
return string .Format( " HelloWorld,thetimeis{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事件的定义

// 摘要:
// Occurswhenthecontrolisclicked.
public event EventHandlerClick;

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


using System.Runtime.InteropServices;

namespace System
{
// 摘要:
// Representsthemethodthatwillhandleaneventthathasnoeventdata.
//
// 参数:
// sender:
// Thesourceoftheevent.
//
// e:
// AnSystem.EventArgsthatcontainsnoeventdata.
[Serializable]
[ComVisible(
true )]
public delegate void EventHandler( object sender,EventArgse);
}

你可能感兴趣的:(delegate)