Как Virtual event, который override в наследниках может вызвать все обработчики в любом их наследников

Вопрос в том как мне набрать обработчиков событий в базовый класс из нескольких наследников таким образом чтобы была возможность вызывать ВСЕ событие из базового класса, любого из его наследников и из вне

Небольшой пример для конкретизации. Самое главное что бы в SomeMethod класса А вызывались все набранные обработчики, но при их добавлении через += они идут не в бейс.

    public abstract class A
    {
        public delegate void D1(bool IsConnected);
        public virtual event D1 EV1;

        public void SomeMethod()
        {
            //TODO
            EV1?.Invoke(true); //Тут нужно что бы вызывались все обработчики добавленные в любом из наследников
            //TODO
        }

        public void InitEvent(D1 d1)
        {
            EV1 = d1;//тут ивент  был null
        }
    }

    public class B : A
    {

        public void SomeMethod_B()
        {
            //TODO
            InitEvent(new D1(B_handler));//Добавляю обработчик из класса Б
            //TODO
        }

        public void B_handler(bool IsConnected)
        {
            //TODO
        }
    }
    public class C : B
    {
        public override event D1 EV1; // Ставлю оверрайд  так как  без него нельзя инвокать

        public void SomeMethod_C()
        {
            //TODO
            EV1 += new D1(C_handler); //Добавляю обработчик из класса C, но он идет не в бейс а в этом скоупе
            EV1?.Invoke(true);
            //TODO
        }
        public void SomeMethod_C2()
        {
            //TODO
            EV1?.Invoke(true);
            //TODO
        }

        public void C_handler(bool IsConnected)
        {
            //TODO
        }
    }

    public class D
    {
        public D()
        {
            var test = new C();
            test.EV1 += Test_EV1;// Добавляю обработчик
            test.SomeMethod_B(); //Добавляю обработчик из класса Б в base abstract
            test.SomeMethod_C(); //Добавляю обработчик
            test.SomeMethod_C2(); //Нужно что бы он вызвал сразу все 2 добавленых хендлера и это Работает
            test.SomeMethod(); //Нужно что бы он вызвал сразу все 3 добавленых хендлера но вызывается  только B_handler
        }

        private void Test_EV1(bool IsConnected)
        {
            //TODO
        }
    }

Или может быть есть иной подход, о котором я не в теме так что бы несколько обработчиков набранных в разных местах и в разное время могли вызыватся из нескольких мест


Ответы (1 шт):

Автор решения: aepot

По сути ваш вопрос можно свести к ошибке CS0070 The event '...' can only appear on the left hand side of += or -=.

Если упростить пример, то он выглядел бы вот так

public abstract class BaseClass
{
    public event Action SomethingChanged;

    public BaseClass()
    {
        SomethingChanged += BaseHandler;
    }

    private void BaseHandler()
    {
        Console.WriteLine("BaseHandler");
    }
}

public class MyClass : BaseClass
{
    public MyClass()
    {
        SomethingChanged += MyHandler;
    }

    public void Execute()
    {
        SomethingChanged?.Invoke(); // Error CS0070  The event 'BaseClass.SomethingChanged' can only appear on the left hand side of += or -= (except when used from within the type 'BaseClass')
    }

    private void MyHandler()
    {
        Console.WriteLine("MyHandler");
    }
}

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

public abstract class BaseClass
{
    public event Action SomethingChanged;

    public BaseClass()
    {
        SomethingChanged += BaseHandler;
    }

    protected void OnSomethingChanged()
    {
        SomethingChanged?.Invoke();
    }

    private void BaseHandler()
    {
        Console.WriteLine("BaseHandler");
    }
}

public class MyClass : BaseClass
{
    public MyClass()
    {
        SomethingChanged += MyHandler;
    }

    public void Execute()
    {
        OnSomethingChanged();
    }

    private void MyHandler()
    {
        Console.WriteLine("MyHandler");
    }
}

Ошибка пропала, проверяем.

static void Main(string[] args)
{
    var item = new MyClass();
    item.Execute();
    Console.ReadKey();
}

Вывод в консоль

BaseHandler
MyHandler
→ Ссылка