最近我发现虚拟事件不像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();
我已经做了更广泛的write-up on my blog,但是说我发现warning on MSDN确认行为是出乎意料的,但它没有说明原因。任何人都可以想到它以这种方式实施的原因吗?它原本是一个为了向后兼容而留下的错误吗?我认为至少可以添加某种编译器警告。
我意识到这很可能是猜测,但我试图为这种奇怪的行为找到合理的解释。
答案 0 :(得分: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);
}
}
}
(注意DoStuff
方法如何使用字段,而不是事件)
因此,当您使用另一个类似字段的事件覆盖事件时,您将获得一个新字段,并且重写事件会修改新字段,而不是基类中的字段:
public class MyClassDerived : MyClassBase
{
private EventHandler _myEvent;
public override event EventHandler MyEvent
{
add { _myEvent += value; }
remove { _myEvent -= value; }
}
}
因此,当您向MyClassDerived
的实例添加处理程序时,_myEvent
中的MyClassBase
字段不会受到影响,因此DoStuff
方法会看到null处理程序。