C#:啥是虚拟事件以及如何使用它们?

Posted

技术标签:

【中文标题】C#:啥是虚拟事件以及如何使用它们?【英文标题】: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# 中的虚拟事件:出了点问题” - viva64.com/en/b/0453 【参考方案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);
    

【讨论】:

以上是关于C#:啥是虚拟事件以及如何使用它们?的主要内容,如果未能解决你的问题,请参考以下文章

js中啥是事件气泡,如何阻止事件气泡

究竟啥是 getattr() 以及如何使用它?

究竟啥是 getattr() 以及如何使用它?

Java中啥是可调用的?

Node.js:啥是 ENOSPC 错误以及如何解决?

如何在 JQuery 数据表的每一行中添加多个按钮以及如何在它们上应用事件