事件是如何在后台工作的






4.64/5 (40投票s)
2007年1月1日
2分钟阅读

83352

289
展示了当你在类中声明一个简单的事件成员时,编译器在幕后做的“魔法”。
引言
本文旨在向您展示编译器在您声明类中的一个简单事件成员时,在幕后做的“魔法”。 它是一篇面向初学者的文章,旨在回答一个经常被问到的问题,所以请不要因为它非常基础而投反对票。
多播委托:事件的基础
要了解事件的底层工作原理,首先要了解多播委托的工作原理。 多播委托是一个组合委托,它由多个单独的委托组合成一个单独的对象。 可以像调用只表示对一个方法的引用的普通委托一样调用该委托,但每次调用它时,它都会调用它所表示的所有方法。 让我们看看实际效果。 假设我们在一个类中有两个方法,分别名为MyMethod1
和MyMethod2
public void MyMethod1()
{
Console.WriteLine("Method 1");
}
public void MyMethod2()
{
Console.WriteLine("Method 2");
}
这些方法没有参数或返回值,因此我们创建一个没有返回值或参数的“空”委托签名
public delegate void EmptyDelegate();
现在,我们要一次调用两个委托,所以我们使用Delegate.Combine()
创建一个组合委托,其中包含对这两个方法的引用
//Create a new multicast delegate that contains references to
//both methods at once.
EmptyDelegate multicast=(EmptyDelegate)Delegate.Combine(
new EmptyDelegate(MyMethod1),
new EmptyDelegate(MyMethod2)
);
//Call the new multicast delegate.
multicast();
当调用多播委托时,这两个方法将按照它们组合的顺序执行,因此控制台输出将是
Method 1
Method 2
事件的实现方式
现在我们已经了解了多播委托的工作原理,让我们看看事件如何使用它们。 事件是多播委托字段的包装器,它只允许外部对象添加和删除处理程序。 为了更好地理解它是如何工作的,让我们看看声明事件的更详细的方法。
首先,定义一个数据类型为委托类型的字段(在本例中为EventHandler
)
private EventHandler myEventHandlers;
这是一个简单的字段,可以保存包含对所有正在侦听event
的处理程序的引用的多播委托。
接下来,我们定义一个特殊的event
声明,它在语法上很像属性,但它是用event
关键字声明的,而不是get
和set
访问器,用于获取和设置属性值,它具有add
和remove
访问器,用于从事件添加和删除处理程序。 请注意使用Delegate.Combine()
来组合委托,并使用Delegate.Remove()
从多播委托中删除单个委托。
//Event declaration - similar in syntax to a property declaration
public event EventHandler MyEvent
{
add
{
//Combine the multi-cast delegate that has the existing handlers
//with the new handler delegate, to make a new multi-cast delegate
//that includes both the existing handlers and the new handler.
myEventHandlers = (EventHandler)
Delegate.Combine(myEventHandlers, value);
}
remove
{
//Create a new multi-cast delegate that contains all
//the existing handlers,
//except for the one that's being removed.
myEventHandlers = (EventHandler)
Delegate.Remove(myEventHandlers, value);
}
}
这将导致与普通类型的声明相同的生成代码
public event EventHandler MyEvent;
所以就是这样:在底层,event
是私有字段(成员变量)中的多播委托,然后是一个特殊的public
访问器,它只允许从多播委托添加和删除处理程序。