【问题标题】:C#: What are virtual events and how can they be used?C#:什么是虚拟事件以及如何使用它们?
【发布时间】:2010-11-10 19:14:08
【问题描述】:

虚拟活动如何运作?你会如何覆盖它?那将如何运作?在什么情况下你会这样做?

它是否可以替代受保护的 OnEvent 方法?那么继承类可以直接覆盖事件并直接引发它吗?或者那会是错误的还是不起作用?

MSDN 是这么说的:

可以使用 virtual 关键字将事件标记为虚拟事件。这使派生类能够通过使用 override 关键字来覆盖事件行为。覆盖虚拟事件的事件也可以被密封,这指定对于派生类它不再是虚拟的。

但这并没有让我变得更聪明。密封的东西很明显。

注意:我已经看到了How virtual events work in C# ? 的问题,但这并不是关于虚拟事件的工作原理。而是那个人如何从使用它们中获得结果。试图从他的示例和答案中弄清楚哪些虚拟事件是什么,但无法真正理解它。

【问题讨论】:

标签: c# events inheritance virtual


【解决方案1】:

虚拟事件只是一个可以在派生类中被覆盖的事件。

您是否对虚拟属性的概念感到满意,以及可以覆盖的 getter 和 setter?如果是这样,您可以以完全相同的方式考虑虚拟事件:除了 getter 和 setter,还有一个“添加”操作和一个“删除”操作。这些可以是虚拟的,因此可以多态处理。您实现它们的方式与实现任何其他虚拟/覆盖成员的方式相同。

例子:

using System;

class Base
{
    public virtual event EventHandler Foo
    {
        add
        {
            Console.WriteLine("Base Foo.add called");
        }
        remove
        {
            Console.WriteLine("Base Foo.remove called");
        }
    }
}

class Derived : Base
{
    public override event EventHandler Foo
    {
        add
        {
            Console.WriteLine("Derived Foo.add called");
        }
        remove
        {
            Console.WriteLine("Derived Foo.remove called");
        }
    }
}

class Test
{
    static void Main()
    {
        Base x = new Derived();

        x.Foo += (sender, args) => {};
    }
}

请注意,事件本身不对引发时发生的事情负责 - 只是添加/删除方面。 (无论如何,在 C# 中;CLR 本身具有引发的概念,但我们暂时忽略它。)

如果您对事件和委托之间的区别有点模糊,您可能还想阅读my article on events

就我个人而言,我非常很少需要虚拟活动。

【讨论】:

  • 如果父类引发了被覆盖的事件,它仍然是同一个事件,对吧?因此,如果您有class Aclass A : B,订阅者将订阅对象的相同事件,无论是作为 A 还是作为 B?
  • 不——加薪是完全分开的。如果 A 类覆盖添加/删除并且不调用 B 类的添加/删除,则调用 B 类引发事件的机制,则不会调用任何处理程序。用普通方法来考虑这一切——事件提供了可以是虚拟的添加/删除,但没有指定引发事件的任何语义。
  • 所以要让它正常工作,你必须做 base.add 和 base.remove 什么的? (如果存在的话……)
  • 谢谢你的好链接顺便说一句,我一有机会就会读它:)
  • 你会使用“base.Foo += value;”在您自己的添加实现等中 - 如果您确实想委托给它。
【解决方案2】:

还要注意,在 C# 中,派生类不能触发纯粹在基类中定义的事件(无论它有什么修饰符)。因此,我们需要为派生类创建一个新事件或覆盖事件,并且在大多数情况下,如果要触发相同的事件,则首选覆盖事件。

【讨论】:

  • 但这可以通过在基类中创建protected Raise... 方法并从派生类中调用来轻松解决。
【解决方案3】:

对于要提出的Foo,我发现在接受的答案中缺少 2 个替代方案。

public class Base 
{
    public virtual event EventHandler Foo;

    public void Bar()
    {
        RaiseFoo();
    }

    protected virtual void RaiseFoo()
    {
        Foo?.Invoke(this, EventArgs.Empty);
    }
}

public class Derived : Base
{
    // In this case we use the base Foo as a backing store.
    public override event EventHandler Foo
    {
        add { base.Foo += value; }
        remove { base.Foo -= value; }
    }
}

public class Derived2 : Base
{
    public override event EventHandler Foo;

    // In this case we raise the overriden Foo.
    protected override void RaiseFoo()
    {
        Foo?.Invoke(this, EventArgs.Empty);
    }
}

class Test
{
    static void Main()
    {
        Base x = new Derived();
        x.Foo += (sender, e) => { };
        x.Bar();
        Base x2 = new Derived2();
        x2.Foo += (sender, e) => { };
        x2.Bar();
    }
}

请注意,这不起作用:

public class Derived3 : Base
{
    public override event EventHandler Foo
    {
        add { base.Foo += value; }
        remove { base.Foo -= value; }
    }

    protected override void RaiseFoo()
    {
        Foo?.Invoke(this, EventArgs.Empty);
    }
}

【讨论】:

    猜你喜欢
    • 2011-07-04
    • 2017-10-26
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-27
    相关资源
    最近更新 更多