虚拟事件如何在C#中运行?

以下是我用于测试的程序。 它打印(如预期):

Raise A Event from A Raise B Event from B 

现在,如果我们改变Main的前两行是:

  A a = new B(); B b = new B(); 

该计划将打印:

 Raise A Raise B Event from B 

这也是预期的,因为重写事件会隐藏基类中的私有支持字段,因此基类触发的事件对派生类的客户端不可见。

现在我将相同的行改为:

  B b = new B(); A a = b; 

程序开始打印:

 Raise A Raise B Event from A Event from B 

这是怎么回事?

 class A { public virtual event EventHandler VirtualEvent; public void RaiseA() { Console.WriteLine("Raise A"); if (VirtualEvent != null) { VirtualEvent(this, EventArgs.Empty); } } } class B : A { public override event EventHandler VirtualEvent; public void RaiseB() { Console.WriteLine("Raise B"); if (VirtualEvent != null) { VirtualEvent(this, EventArgs.Empty); } } } class Program { static void Main(string[] args) { A a = new A(); B b = new B(); a.VirtualEvent += (s, e) => Console.WriteLine("Event from A"); b.VirtualEvent += (s, e) => Console.WriteLine("Event from B"); a.RaiseA(); b.RaiseB(); } } 

我们有一个(B)实例,它有以下几个字段:

  • A.VirtualEvent:null
  • B.VirtualEvent:两个事件处理程序

a.RaiseA()的调用打印“Raise A” – 但仅此而已,因为A中的私有字段为空。

b.RaiseB()的调用打印剩余的三行,因为事件已订阅两次(一次打印“来自A的事件”,一次打印“来自B的事件”)。

这有帮助吗?

编辑:更清楚 – 将虚拟事件视为一对虚拟方法。 它非常像这样:

 public class A { private EventHandler handlerA; public virtual void AddEventHandler(EventHandler handler) { handlerA += handler; } public virtual void RemoveEventHandler(EventHandler handler) { handlerA -= handler; } // RaiseA stuff } public class B : A { private EventHandler handlerB; public override void AddEventHandler(EventHandler handler) { handlerB += handler; } public override void RemoveEventHandler(EventHandler handler) { handlerB -= handler; } // RaiseB stuff } 

现在更清楚了吗? 它不是那样的,因为据我所知,你不能仅仅覆盖事件的“部分”(即其中一种方法),但它给出了正确的总体印象。

你将两个事件处理程序连接到同一个事件。 由于A和B指向同一个对象,因此当您调用b.RaiseB()时,两个事件处理程序都会被触发。 所以首先你要调用RaiseA,这是一种basecalss方法。 打印出Raise A.然后它实际上并没有触发事件,因为它是空的。 然后,你正在筹集B,但是两个处理程序连接到它,因此它首先打印Raise B,当事件触发时,两个处理程序都被调用。

尝试使您的RaiseAfunction受到保护+虚拟。

经验法则:如果派生类重写事件访问器,它还必须覆盖调用事件的函数。