浅谈C#中的Delegate和Event

  委托(Delegate)和事件(Event)是学习c#中的一道门槛,作为初学者的我让它整的是头晕脑胀。在CSDN上发帖,最后看了张子阳的博客才算明白,下面就谈谈我学习的收获。

  (1)委托(Delegate)的理解,c#是面向对象的语言,在编程中类和对象是无处不在的。同样,在这里委托(Delegate)也是一个类(Class),它的对象实例(Instance)是方法(Method),名字也叫委托(Delegate)。

    1)我们怎么证明它是个类呢?

        首先,声明一个委托:public delegate void GreetingDelegate(string name);

        然后用FReflector反编译一下。FReflector下载,编译器会生成如下完整的类。

代码
public class GreetingDelegate:System.MulticastDelegate
{
public GreetingDelegate(object @object, IntPtr method);
public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string name);
}

 

 

         2)委托的实例是与委托具有相同签名的方法,签名就是方法的返回类型和传入参数。在此例中,应该是这样

     public void GreetName(string name)

     委托(Delegate)的作用,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

  (2)令人迷惑的事件(Event),下面是关于事件和委托的完整代码:

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DelegateAndEvent
{
public delegate void GreetingDelegate(string name);
class GreetingEvent
{
public event GreetingDelegate MakeGreetEvent;//声明一个事件

public void OnMakeGreetEvent(string name)//声明调用事件的方法
{
if (MakeGreetEvent != null)
{
MakeGreetEvent(name);
}
}
}
}


客户端调用代码:

 

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DelegateAndEvent
{
class Program
{
static void Main(string[] args)
{
GreetingEvent greetingEvent
= new GreetingEvent();
greetingEvent.MakeGreetEvent
+= new GreetingDelegate(ChineseGreeting);//注册事件
greetingEvent.MakeGreetEvent += new GreetingDelegate(EnglishGreeting);//注册事件

greetingEvent.OnMakeGreetEvent(
"Dhuxin");

Console.ReadKey();

}

public static void ChineseGreeting(string name)
{
Console.WriteLine(
"早上好,{0}!", name);
}
public static void EnglishGreeting(string name)
{
Console.WriteLine(
"Good Morning,{0}!", name);
}
}
}

 

 

令人迷惑的地方,当我们把event关键字去掉时,程序完全运行正常,那为什么还需要event?

(1)我们再次用reflector反编译一下看看,MakeGreetEvent事件是怎么回事。

 

对应的代码: 

代码
private GreetingDelegate MakeGreet; //对事件的声明 实际是 声明一个私有的委托变量

public void add_MakeGreetEvent(GreetingDelegate value)//add_MakeGreetEvent方法对应“+=”
{
GreetingDelegate delegate3;
GreetingDelegate makeGreetEvent
= this.MakeGreetEvent;
do
{
delegate3
= makeGreetEvent;
GreetingDelegate delegate4
= (GreetingDelegate) Delegate.Combine(delegate3, value);
makeGreetEvent
= Interlocked.CompareExchange<GreetingDelegate>(ref this.MakeGreetEvent, delegate4, delegate3);
}
while (makeGreetEvent != delegate3);
}

public void remove_MakeGreetEvent(GreetingDelegate value)//remove_MakeGreetEvent对应“-=”
{
GreetingDelegate delegate3;
GreetingDelegate makeGreetEvent
= this.MakeGreetEvent;
do
{
delegate3
= makeGreetEvent;
GreetingDelegate delegate4
= (GreetingDelegate) Delegate.Remove(delegate3, value);
makeGreetEvent
= Interlocked.CompareExchange<GreetingDelegate>(ref this.MakeGreetEvent, delegate4, delegate3);
}
while (makeGreetEvent != delegate3);
}

 

 现在明确了,MakeGreet 事件确实是一个GreetingDelegate 类型的委托变量,不管是不是声明为public,还是protected,它总是被声明为private。另外,它还有两个方法,分别是add_MakeGreet 和remove_MakeGreet,这两个方法分别用于注册委托类型的方法和取消注册。实际上也就是: “+= ”对应 add_MakeGreet, “-=”对应 remove_MakeGreet。而这两个方法的访问限制取决于声明事件时的访问限制符。

 

这样做的好处:
(1)GreetingDelegate声明为私有,使得客户端不能对它随意赋值,避免破坏了对象的封装性。
(2)仅仅用Delegate而不用Event,第一个方法注册用“=” ,是赋值语法,因为要进行实例化,第二个方法注册则用的是“+=” 。现在用Event统一用"+=",使得形式上得到统一。

 

实际上,它和C#中属性(property)对字段(field)的封装很类似,Event是对Delegate的封装,只不过不是公开而是保护。

文中代码,和张子阳的电子书还有我搜集的关于委托和事件的资料打包下载下载地址

posted on 2010-07-19 21:47  DhuXin  阅读(577)  评论(0编辑  收藏  举报