事件变量和委托对象的区别(整理)

event与delegate的区别
 首先,通过加入event关键字,在编译的时候编译器会自动针对事件生成一个私有的字段(与此事件相关的委托),以及两个访问器方法,即add访问器方法以及remove访问器方法,用于对事件的注册及注销(对事件使用+=及-=操作时就是调用的这两个方法)。
我想你们的问题主要是,实际上声明一个委托类型的字段也可以实现这些功能。
实际上之所以采用event而不直接采用委托,实际上还是为了封装。可以设想一下,如果直接采用公共的委托字段,类型外部就可以对此字段进行直接的操作了,比如将其直接赋值为null。
而使用event关键字就可以保证对事件的操作仅限于add访问器方法以及remove访问器方法(即只能使用+=及-=)

eventdelegateC#中的两个关键字,在微软的例程中常见它们一起出现,那么他们之间有什么关系呢?

 

想看专业的解释就看:
.NET Famework SDK文档-〉参考-〉编译器和语言参考-C#-C#语言规范-10.7.1类似字段的事件 
里面有详细的解释。 
这里我想就编译时发生的事情做一下描述。 

上面的参考中有一句:引发一个事件调用一个由该事件表示的委托完全等效。

什么意思呢?

我觉得可以这样表述:事件的引发是通过调用委托实现的,而委托不仅仅可以用来实现事件的引发。
我写了下面一段测试代码,我们可以看看编译器到底对
event做了些什么。

事件变量和委托对象的区别(整理)    public class Class1
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)    
事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)        
public delegate void abc();
事件变量和委托对象的区别(整理)        
public event abc thisevent;
事件变量和委托对象的区别(整理)        
public Class1()
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)        
事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)
            thisevent += new abc(d);
事件变量和委托对象的区别(整理)            thisevent 
+= new abc(e);
事件变量和委托对象的区别(整理)            thisevent 
-= new abc(d);
事件变量和委托对象的区别(整理)            thisevent 
= thisevent - new abc(e);
事件变量和委托对象的区别(整理)        }

事件变量和委托对象的区别(整理)
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)        
public void d()事件变量和委托对象的区别(整理){}
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)        
public void e()事件变量和委托对象的区别(整理){}
事件变量和委托对象的区别(整理)    }

事件变量和委托对象的区别(整理)

 

我们用ildasm工具打开生成的IL代码:
事件变量和委托对象的区别(整理)

可以看到delegate abc实际上是从MulticastDelegate继承而来的一个类。

而在我们自己声明的thisevent事件、d()e()方法之外,多出了一个thisevent字段和两个方法add_thisevent()remove_thisevent()

正如上面提到的那篇参考内描述的那样,一个事件的声明是可以转化为一个代理字段的声明加上添加、删除两种方法的事件操作。


我们查看
thisevent事件的IL代码:

 

事件变量和委托对象的区别(整理).event test4eventil.Class1/abc thisevent
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)
事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)  .addon instance 
void test4eventil.Class1::add_thisevent(class test4eventil.Class1/abc)
事件变量和委托对象的区别(整理)  .removeon instance 
void test4eventil.Class1::remove_thisevent(class test4eventil.Class1/abc)
事件变量和委托对象的区别(整理)}
 // end of event Class1::thisevent
事件变量和委托对象的区别(整理)

可以看到,实际上add_thisevent()remove_thisevent()是包含在thisevent事件中的两个方法。

那么,这两个方法与delegate有什么关系呢?

我们看看add_thisevent()IL代码:

事件变量和委托对象的区别(整理).method public hidebysig specialname instance void 
事件变量和委托对象的区别(整理)        add_thisevent(
class test4eventil.Class1/abc 'value') cil managed synchronized
事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)
事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)  
// 代码大小       24 (0x18)
事件变量和委托对象的区别(整理)
  .maxstack  3
事件变量和委托对象的区别(整理)  IL_0000:  ldarg.
0
事件变量和委托对象的区别(整理)  IL_0001:  ldarg.
0
事件变量和委托对象的区别(整理)  IL_0002:  ldfld      
class test4eventil.Class1/abc test4eventil.Class1::thisevent
事件变量和委托对象的区别(整理)  IL_0007:  ldarg.
1
事件变量和委托对象的区别(整理)  IL_0008: call       
class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
事件变量和委托对象的区别(整理)  IL_000d:  castclass  test4eventil.Class1
/abc
事件变量和委托对象的区别(整理)  IL_0012:  stfld      
class test4eventil.Class1/abc test4eventil.Class1::thisevent
事件变量和委托对象的区别(整理)  IL_0017:  ret
事件变量和委托对象的区别(整理)}
 // end of method Class1::add_thisevent
事件变量和委托对象的区别(整理)

反编译后如下:

事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)public void add_thisevent(abc value) 事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)    
this.thisevent = (abc) Delegate.Combine(this.thisevent, value);
事件变量和委托对象的区别(整理)}

事件变量和委托对象的区别(整理)

remove_thisevent()则是:

 

事件变量和委托对象的区别(整理)事件变量和委托对象的区别(整理)public void remove_thisevent(abc value) 事件变量和委托对象的区别(整理){
事件变量和委托对象的区别(整理)    
this.thisevent = (abc) Delegate.Remove(this.thisevent, value);
事件变量和委托对象的区别(整理)}

事件变量和委托对象的区别(整理)


也就是说,实际上,添加一个事件的绑定,实际上就是向该事件表示的委托列表中添加一项委托。而取消一个事件的绑定,就是从委托列表中删除一项委托。

所以,对event的绑定都是通过在delegate列表中添加、删除项来实现的。

另外,需要注意的一点是:除了在event对象声明的类内部,event对象只能用在+=-=的左边。

事件变量和委托对象的区别(整理)

转载于:https://www.cnblogs.com/lin614/archive/2007/01/30/634576.html