C#: What are virtual events and how can they be used?

11,259

A virtual event is simply one which can be overridden in a derived class.

Are you happy with the concept of a virtual property, with a getter and setter which can be overridden? If so, you can think of a virtual event in exactly the same way: instead of a getter and setter, there's an "add" operation and a "remove" operation. These can be virtual, so handled polymorphically. You implement them the same way you implement any other virtual/overridden member.

Example:

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) => {};
    }
}

Note that the event itself is not responsible for what happens when it is raised - just the add/remove side. (In C#, anyway; the CLR itself has the notion of raising, but we'll ignore that for the moment.)

You may also want to read my article on events if you're slightly hazy on the difference between an event and a delegate.

Personally I find it very rare that I want a virtual event.

Share:
11,259

Related videos on Youtube

Lemon
Author by

Lemon

Software Developer, Geek, HSP, SDA, ..., open, honest, careful, perfectionist, ... Currently into indoor rowing and rock climbing, just to mention something non-computer-related... Not the best at bragging about myself... so... not sure what more to write... 🤔

Updated on December 24, 2020

Comments

  • Lemon
    Lemon over 3 years

    How does a virtual event work? How would you override it? How would that work? And in what cases would you do that?

    Would it for example be an ok replacement for protected OnEvent methods? So that inheriting classes could just override the event and raise it directly? Or would that be wrong or just not work?

    The MSDN says this about it:

    An event can be marked as a virtual event by using the virtual keyword. This enables derived classes to override the event behavior by using the override keyword. An event overriding a virtual event can also be sealed, which specifies that for derived classes it is no longer virtual.

    But that didn't make me much wiser. The sealed stuff is obvious though.

    Note: I've seen the How virtual events work in C# ? question, but it wasn't really about how virtual events work. Rather it was how that person got the result he got from using them. Tried to figure out what virtual events were from his example and the answers, but couldn't really make sense out of it.

  • Lemon
    Lemon almost 15 years
    If the parent class raises the overridden event, it would still be the same event, right? So if you had class A and class A : B, subscribers would subscribe to the same event of an object both if it was done as A or as B?
  • Jon Skeet
    Jon Skeet almost 15 years
    No - raising is entirely separate. If class A overrides the add/remove and doesn't call up to class B's add/remove, then class B's mechanism for raising the event was called, then none of the handlers would be called. Think of it all in terms of plain methods - the event provides add/remove which can be virtual, but doesn't specify anything about the semantics of raising the event.
  • Lemon
    Lemon almost 15 years
    So for it to work properly you would have to do base.add and base.remove or something? (If that exists...)
  • Lemon
    Lemon almost 15 years
    Thanks for nice link btw, will read it as soon as I get the chance :)
  • Jon Skeet
    Jon Skeet almost 15 years
    You'd use "base.Foo += value;" within your own add implementation, etc - if you definitely want to delegate to it.
  • MarioDS
    MarioDS over 6 years
    But that can easily be resolved by creating a protected Raise... method in the base class and call it from the derived class.
  • MarioDS
    MarioDS over 6 years
    "Personally I find it very rare that I want a virtual event". @JonSkeet: I could see why, but one case they are really helpful is mocking. When you use e.g. Moq to mock a class and want to raise some event on that class it will have to be virtual in order to raise it. Then of course you'd usually mock interfaces. This might be the most important reason why an event can be virtual: if an interface can declare them, it would be weird if they can't be abstract, and if they can be abstract, it would be weird they can't be virtual.
  • Jon Skeet
    Jon Skeet over 6 years
    @MarioDS: Why would you want to mock the event subscription itself though? I tend to think that mocking is overused, and this sounds like one of those places. There are easy ways of checking whether an event subscription/unsubscription has occurred in most cases. I also don't see events in interfaces very often. I'm glad all this is available, but that doesn't change the fact that I find it very rare to want it.
  • MarioDS
    MarioDS over 6 years
    @JonSkeet I'm currently working on a WinForms project, and while the .NET events system has rough edges and flaws left and right (easy to misuse), it's a natural fit on that platform. I'm not testing event (un)subscription, I'm testing what certain components do when a dependency raises an event. Moq allows you to raise events directly, but raising can only be done from the type that declares the event. You say "raising and subscription management are entirely separate" and you're right except for that very important restriction.
  • Jon Skeet
    Jon Skeet over 6 years
    @MarioDS: I'm a little lost on exactly what you're testing, but if it's useful for you, fine. I'd at least be wary that you're not over-mocking something that could easily be handled with the concrete class, but obviously I can't see your code. None of this changes my experience which is that it's very rare for me to use virtual events.
  • MarioDS
    MarioDS over 6 years
    @JonSkeet Sure, I understand that. My default way of testing (unit testing at least), and what we do at the place I work, is to supply mocks of dependencies to a component under test through DI. Do you use different strategies for unit testing? I know it's off-topic here, but I'm eager to learn, especially from people with your experience level.