为什么类似虚拟字段的事件与C#中的事件一样?

Tho*_*rin 2 c# events virtual

最近我发现虚拟事件不像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;
}
Run Code Online (Sandbox Code Playgroud)

鉴于此定义,以下代码的行为与我的预期不符:

MyClassBase obj = new MyClassDerived();
obj.MyEvent += (s, e) => { /* Never gets called */ };

// Call method on base class that raises MyEvent
obj.DoStuff();
Run Code Online (Sandbox Code Playgroud)

在我的博客上做了一些更广泛的写作,但足以说我在MSDN上发现了一个警告,确认行为是意外的,但它没有说明原因.任何人都可以想到它以这种方式实施的原因吗?它原本是一个为了向后兼容而留下的错误吗?我认为至少可以添加某种编译器警告.

我意识到这很可能是猜测,但我试图为这种奇怪的行为找到合理的解释.

Tho*_*que 5

类似于字段的事件由编译器扩展为如下所示:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

public class MyClassDerived : MyClassBase
{
    private EventHandler _myEvent;
    public override event EventHandler MyEvent
    {
        add { _myEvent += value; }
        remove { _myEvent -= value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,当您向一个实例添加处理程序时MyClassDerived,该_myEvent字段MyClassBase不会受到影响,因此该DoStuff方法会看到一个空处理程序.