简体   繁体   English

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

[英]How virtual events work in C#?

Below is the program I used for the test. 以下是我用于测试的程序。 It prints (as expected): 它打印(如预期):

Raise A
Event from A
Raise B
Event from B

Now, if we change first two lines of the Main to be: 现在,如果我们改变Main的前两行是:

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

the Program will print: 该计划将打印:

Raise A
Raise B
Event from B

which is also expected, as overriding event hides the private backing field in the base class and therefore events fired by the base class are not visible to clients of the derived class. 这也是预期的,因为重写事件会隐藏基类中的私有支持字段,因此基类触发的事件对派生类的客户端不可见。

Now I am changing the same lines to: 现在我将相同的行改为:

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

and the program starts printing: 程序开始打印:

Raise A
Raise B
Event from A
Event from B

What's going on? 这是怎么回事?

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();
    }
}

We have a single instance (of B) which has the following fields: 我们有一个(B)实例,它有以下几个字段:

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

The call to a.RaiseA() just prints "Raise A" - but nothing more, because the private field in A is null. a.RaiseA()的调用打印“Raise A” - 但仅此而已,因为A中的私有字段为空。

The call to b.RaiseB() prints the remaining three lines, because the event has been subscribed to twice (once to print "Event from A" and once to print "Event from B"). b.RaiseB()的调用打印剩余的三行,因为事件已订阅两次(一次打印“A中的事件”,一次打印“B中的事件”)。

Does that help? 这有帮助吗?

EDIT: To make it clearer - think of the virtual event as a pair of virtual methods. 编辑:更清楚 - 将虚拟事件视为一对虚拟方法。 It's very much like this: 它非常像这样:

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
}

Now is it clearer? 现在更清楚了吗? It's not quite like that because as far as I'm aware you can't override just "part" of an event (ie one of the methods) but it gives the right general impression. 这是不太一样,因为据我所知,你不能覆盖只是一个事件的“部分”(即的方法之一),但它给出了正确的总体印象。

You hooked up two event handlers to the same event. 您将两个事件处理程序连接到同一事件。 Since A and B are pointing to the same object, when you call b.RaiseB() both event handlers get fired. 由于A和B指向同一个对象,因此当您调用b.RaiseB()时,两个事件处理程序都会被触发。 So first you're calling RaiseA which is a basecalss method. 所以首先你要调用RaiseA,它是一种basecalss方法。 That prints Raise A. It then doesn't actually fire off the event because it's null. 打印出Raise A.然后它实际上并没有触发事件,因为它是空的。 Then, you're raising B but TWO handlers are hooked up to it, therefore it first prints Raise B, and when the event fires, both handlers get called. 然后,你正在筹集B,但是两个处理程序连接到它,因此它首先打印Raise B,当事件触发时,两个处理程序都被调用。

Try making your RaiseA function protected + virtual. 尝试使您的RaiseA功能受到保护+虚拟。

A rule of thumb: If derived class overrides event accessors, it must also override the function that invokes the event. 经验法则:如果派生类重写事件访问器,它还必须覆盖调用事件的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM