Подтвердить что ты не робот

С#: Что такое виртуальные события и как их можно использовать?

Как работает виртуальное событие? Как бы вы его переопределили? Как это будет работать? И в каких случаях вы это сделаете?

Будет ли это, например, замена ok для защищенных методов OnEvent? Итак, чтобы наследующие классы могли просто переопределить событие и поднять его напрямую? Или это будет неправильно или просто не работает?

MSDN говорит об этом:

Событие можно пометить как виртуальное событие, используя ключевое слово virtual. Это позволяет производным классам переопределять поведение события с помощью ключевого слова override. Событие, переопределяющее виртуальное событие, также может быть запечатано, что указывает, что для производных классов оно больше не является виртуальным.

Но это не сделало меня намного мудрее. Запечатанный материал очевиден.

Примечание. Я видел Как работают виртуальные события в С#?, но это было не совсем о том, как виртуальные события Работа. Скорее всего, именно этот человек получил результат, который он получил от их использования. Попытался выяснить, какие виртуальные события были из его примера и ответов, но не мог действительно понять из этого.

4b9b3361

Ответ 1

Виртуальное событие - это просто тот, который может быть переопределен в производном классе.

Вы довольны концепцией виртуального имущества, с геттером и сеттером, которые можно переопределить? Если это так, вы можете думать о виртуальном событии точно так же: вместо геттера и сеттера есть операция "добавить" и операцию "удалить". Они могут быть виртуальными, поэтому обрабатываются полиморфно. Вы реализуете их так же, как и любой другой виртуальный/переопределенный элемент.

Пример:

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

Обратите внимание, что само событие не несет ответственности за то, что происходит, когда оно поднято - только сторона добавления/удаления. (В С#, во всяком случае, сама CLR имеет понятие поднятия, но мы будем игнорировать это на данный момент.)

Вы также можете прочитать мою статью о событиях, если вы слегка замаскируете разницу между событием и делегатом.

Лично я нахожу очень редким, что хочу виртуальное событие.

Ответ 2

Также обратите внимание, что в С# производный класс не может запустить событие, чисто определенное в базовом классе (независимо от того, какой у него модификатор). Таким образом, нам нужно либо новое, либо переопределяющее событие для производного класса, и в большинстве случаев предпочтительным является приоритетное, если одно и то же событие должно быть запущено.

Ответ 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);
    }
}