首页 > 代码库 > C# 事件

C# 事件

一、前言:前面的随笔中说完了委托,现在看看事件到底可以干什么,在前面的随笔中,使用委托的过程中,有一个很别扭,也很显然易见的问题,就是委托第一次必须初始化用"=",绑定二次事件用"+="这个是非常的,怎么说呢?就是别扭;幸运的是事件就是来解决这个问题(不用初始化,直接使用"+=")的;当然将委托封装成SayHelloManager类中的实例也可以解决这个问题,具体做法参照前面的随笔;

 

二、概述

1、事件:事件从代码角度看,就是声明了一个委托类型的变量;具体实现代码如下:

using System;
namespace Event{
    public delegate void myEventHandler(string _name);
    class Event1{
       static void Main(string[] args){
            BulidSoftManager bsm=new BulidSoftManager();
            bsm.myevent = BulidByC;   //编译报错  错误详情:Event.BulidSoftManager.myevent只能出现在+=或者-=的左边(在Event.BulidSoftManager中使用除外)
            bsm.myevent+=BulidByCSharp;
            bsm.BulidSoftWalk("OA", bsm.myevent);//上同
       }
       static void BulidByC(string _softName){
             Console.WriteLine(_softName+"  这款软件通过C来编写");
       }
       static void BulidByCSharp(string _softName){
              Console.WriteLine(_softName+"  这款软件通过C#来编写");
       }
    }
    public class BulidSoftManager{
         public event myEventHandler myevent;
         public void BulidSoftWalk(string _softName,myEventHandler bulid){
                bulid(_softName);
         }
    }
}

分析:更具上面的错误提示,这个时候就要借助反编译工具reflactor来看看myevent事件内部的构造;

技术分享

上面是myevent的基本结构,由两个无返回值的方法(add_myevent和remove_myevent)和一个myevent属性组成。然后点击myevent属性发现下图

技术分享

恍然大悟,其实myevent事件被编译成了myEventHandler委托的私有委托变量,所以不管你给事件加什么修饰符,最后他都会被编译成目标委托的私有委托变量;

下面是其余两个方法的结构图,贴出来看下:

技术分享

技术分享

 好了,根据上面的图解和推断,大致就知道事件的内部大概的运行机制

<1>myevent确实是myEventHandler类型的委托,只不过不管给myevent添加什么修饰符,他都是私有的,因为它会被编译器强制编译成private,

 而add_myevent()和remove_myevent则对应"+="和"-="操作,这两个方法分别用于注册委托类型的方法和取消注册,而这两个方法的访问限制取决于你定义的事件是否对外暴露。

如果你定义的事件是private,那么在外部类中就无法调用这个事件当然也就无法吊用这两个方法;

 

<2>add_myevent()方法概述

从上图可以看出,在add_myevent()方法内部,实际上调用了System.Delegate的Combine()静态方法,这个方法用于将当前的变量添加到委托链表中。我们前面提到过两次,说委托实际上是一个类;

 

2、综上所述:得出这么几个结论

<1>事件在定义之后,会被编译器编译成委托类型的变量,而这个变量是定义(封装)该事件的类所私有的,当外部类使用该事件时无法进行赋值操作(也就是"="),但是在定义该事件的类中可以使用;

<2>在事件允许访问的情况下,可以对事件进行"+="和"-="操作,原因上文已说明;

 

三、实例

现在需要设计一个汽车燃油监测系统,当油量小于10升时:

1、汽车警报器报警  -滴滴声

2、仪表盘显示相应的警告信息

using System;
namespace Event{
   class Event1{
        static void Main(string[] args){
             Car car=new Car();
             car.drive();
        }
   }
   //定义一个汽车类,封装油量、温度等的需要的字段
   public class Car{
          public int _oilmass;
          public int OilMass{
                  get{return _oilmass;}
                  set{_oilmass=value;}
          }
          public void drive(){
                   if(OilMass<=10){
                        MakeAlarm(OilMass);
                        ShowMsg(OilMass);
                    }
          }
          public void MakeAlarm(int _oilmass){
                   Console.Write("油量不足{0}L,请及时加油",_oilmass);
          }
          public void ShowMsg(int _oilmass){
                   Console.Write("油量不足{0}L",_oilmass);
          }
   }

}

 

C# 事件