热门关键字:  PHP  Cisco  seo  网络广告 虚拟主机 中文域名
当前位置 :| 主页>编程开发>ASP.NET>C#语言>

C#中的委托和事件

来源:blog.csdn.net 作者: 时间:2008-06-25 点击:

 到了这里,我们不禁想到:面向对象设计,讲究的是对象的封装,既然可以声明委托类型的变量(在上例中是delegate1),我们何不将这个变量封装到 GreetManager类中?在这个类的客户端中使用不是更方便么?于是,我们改写GreetManager类,像这样:

以下为引用的内容:  public class GreetingManager

{

 //在GreetingManager类的内部声明delegate1变量

        public GreetingDelegate delegate1;      
public void GreetPeople(string name, GreetingDelegate MakeGreeting)

 {

                      MakeGreeting(name);

       }

 }
 


现在,我们可以这样使用这个委托变量:

以下为引用的内容: static void Main(string[] args)

{

        GreetingManager gm = new  GreetingManager();

       gm.delegate1 = EnglishGreeting;

       gm.delegate1 += ChineseGreeting;

       gm.GreetPeople("Jimmy Zhang", gm.delegate1);

}
 


  尽管这样达到了我们要的效果,但是似乎并不美气,光是第一个方法注册用“=”,第二个用“+=”就让人觉得别扭。此时,轮到Event出场了,C# 中可以使用事件来专门完成这项工作,我们改写GreetingManager类,它变成了这个样子:

以下为引用的内容: public class GreetingManager

{

        //这一次我们在这里声明一个事件

        public event GreetingDelegate MakeGreet;

public void GreetPeople(string name, GreetingDelegate MakeGreeting)

{

               MakeGreeting(name);

       }

}
 


  很容易注意到:MakeGreet 事件的声明与之前委托变量delegate1的声明唯一的区别是多了一个event关键字。看到这里,你差不多明白到:事件其实没什么不好理解的,声明一个事件不过类似于声明一个委托类型的变量而已。

  我们想当然地改写Main方法:

以下为引用的内容:  static void Main(string[] args)

{

        GreetingManager gm = new  GreetingManager();

        gm.MakeGreet = EnglishGreeting;

       // 编译错误1

        gm.MakeGreet += ChineseGreeting;

       gm.GreetPeople("Jimmy Zhang", gm.MakeGreet);

      //编译错误2

 }
 


  这次,你会得到编译错误:事件“Delegate.GreetingManager.MakeGreet”只能出现在 += 或 -= 的左边(从类型“Delegate.GreetingManager”中使用时除外)。

  事件和委托的编译代码

  这时候,我们不得不注释掉编译错误的行,然后重新进行编译,再借助Reflactor来对 event的声明语句做一探究,看看为什么会发生这样的错误:

public event GreetingDelegate MakeGreet;

  可以看到,实际上尽管我们在GreetingManager里将 MakeGreet 声明为public,但是,实际上MakeGreet会被编译成 私有字段,难怪会发生上面的编译错误了,因为它根本就不允许在GreetingManager类的外面以赋值的方式访问。

  我们进一步看下MakeGreet所产生的代码:

以下为引用的内容:  private GreetingDelegate MakeGreet; 
      //对事件的声明 实际是 声明一个私有的委托变量

[MethodImpl(MethodImplOptions.Synchronized)]

 public void add_MakeGreet(GreetingDelegate value)

{

     this.MakeGreet = (GreetingDelegate) Delegate.Combine(this.MakeGreet, value);

 }

[MethodImpl(MethodImplOptions.Synchronized)]

public void remove_MakeGreet(GreetingDelegate value)

{

     this.MakeGreet = (GreetingDelegate) Delegate.Remove(this.MakeGreet, value);

}
 


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

  在add_MakeGreet()方法内部,实际上调用了System.Delegate的Combine()静态方法,这个方法用于将当前的变量添加到委托链表中。我们前面提到过两次,说委托实际上是一个类,在我们定义委托的时候:

public delegate void GreetingDelegate(string name);

  当编译器遇到这段代码的时候,会生成下面这样一个完整的类:

以下为引用的内容:  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);

}
 
 
  关于这个类的更深入内容,可以参阅《CLR Via C#》等相关书籍,这里就不再讨论了。

委托、事件与Observer设计模式


最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
赞助商连接