为什么虚拟字段类事件会以c#中的方式工作?

本文关键字:方式 工作 字段 虚拟 事件 为什么 | 更新日期: 2023-09-27 18:08:16

最近我发现虚拟事件在c#中并不像人们想象的那样工作。考虑以下代码:

public abstract class MyClassBase
{
    public virtual event EventHandler<EventArgs> MyEvent;
    public void DoStuff()
    {
        if (MyEvent != null)
        {
            MyEvent(this, EventArgs.Empty);
        }
    }
}
public class MyClassDerived : MyClassBase
{
    public override event EventHandler<EventArgs> MyEvent;
}
根据这个定义,以下代码的行为与我所期望的不同:
MyClassBase obj = new MyClassDerived();
obj.MyEvent += (s, e) => { /* Never gets called */ };
// Call method on base class that raises MyEvent
obj.DoStuff();

我在我的博客上做了一些更广泛的报道,但足以说明的是,我在MSDN上发现了一个警告,确认了这种行为是意外的,但它没有说明任何原因。有人能想到为什么要这样实现吗?它最初是一个为了向后兼容而遗留下来的bug吗?我想至少应该添加一些编译器警告。

我知道这很可能是猜测,但我正试图为这种奇怪的行为找到一个合理的解释。

为什么虚拟字段类事件会以c#中的方式工作?

类字段事件被编译器扩展为如下内容:

public abstract class MyClassBase
{
    private EventHandler _myEvent;
    public virtual event EventHandler MyEvent
    {
        add { _myEvent += value; }
        remove { _myEvent -= value; }
    }
    public void DoStuff()
    {
        if (_myEvent != null)
        {
            _myEvent(this, EventArgs.Empty);
        }
    }
}

(注意DoStuff方法如何使用字段,而不是事件)

因此,当您使用另一个类似字段的事件覆盖该事件时,您将获得一个新字段,并且被覆盖的事件修改新字段,而不是基类中的字段:

public class MyClassDerived : MyClassBase
{
    private EventHandler _myEvent;
    public override event EventHandler MyEvent
    {
        add { _myEvent += value; }
        remove { _myEvent -= value; }
    }
}

因此,当您向MyClassDerived的实例添加处理程序时,MyClassBase中的_myEvent字段不受影响,因此DoStuff方法看到空处理程序。