65.9K
CodeProject 正在变化。 阅读更多。
Home

事件是如何在后台工作的

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (40投票s)

2007年1月1日

2分钟阅读

viewsIcon

83352

downloadIcon

289

展示了当你在类中声明一个简单的事件成员时,编译器在幕后做的“魔法”。

引言

本文旨在向您展示编译器在您声明类中的一个简单事件成员时,在幕后做的“魔法”。 它是一篇面向初学者的文章,旨在回答一个经常被问到的问题,所以请不要因为它非常基础而投反对票。


多播委托:事件的基础

要了解事件的底层工作原理,首先要了解多播委托的工作原理。 多播委托是一个组合委托,它由多个单独的委托组合成一个单独的对象。 可以像调用只表示对一个方法的引用的普通委托一样调用该委托,但每次调用它时,它都会调用它所表示的所有方法。 让我们看看实际效果。 假设我们在一个类中有两个方法,分别名为MyMethod1MyMethod2

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关键字声明的,而不是getset访问器,用于获取和设置属性值,它具有addremove访问器,用于从事件添加和删除处理程序。 请注意使用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访问器,它只允许从多播委托添加和删除处理程序。

© . All rights reserved.