Подписаться / отписаться (добавить / удалить) к событию внутри метода расширения

Я хочу создать свободный метод расширения для подписки на событие (и, что не менее важно, отписаться от него). Это расширение с использованием .RespondBy(Method) вместо += new Eventhandler(Method)

Я хочу сделать это: object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);

Вместо этого: object.WhenSomethingChanges += new EventHandler(DoingThisOtherThing);

Я занимался поиском в Google, и хотя я не совсем понял сложные детали, теперь я понимаю, что это связано с тем, обращаетесь ли вы к локальному полю или к публичному мероприятию.

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

CommuncationsStatusPresenter (изображение)

Образ попытки использования, не компилируется

CommuncationsStatusPresenter (Код)

using System;
using InspectionStation.Models;
using InspectionStation.Views;
using MachineControl.OPC;

namespace InspectionStation.Presenters
{
    public class CommuncationsStatusPresenter
    {
        // Fields
        private ICommunicationsModel m_model;
        private ICommunicationsView m_view;

        // Constructor
        public CommuncationsStatusPresenter
            (ICommunicationsModel p_model, ICommunicationsView p_view)
        {
            m_model = p_model;
            m_view = p_view;
            HookEvents();
        }
        private void HookEvents()
        {
            m_model
                .When_Communications_Pulses_Heartbeat
                .RespondBy(Setting_the_state_of_an_Indicator);
        }

        // Eventhandler
        void Setting_the_state_of_an_Indicator(Tag sender, EventArgs e)
        {
            bool State = sender.BooleanValue;
            m_view.Set_Communications_Status_Indicator = State;
        }
    }
}

RespondBy

using System;

namespace Common.Extensions
{
    public static partial class ExtensionMethods
    {
        public static
            void RespondBy<TSender, TEventArgs>(this
            GenericEventHandler<TSender, TEventArgs> p_event,
            GenericEventHandler<TSender, TEventArgs> p_handler
            ) where TEventArgs : EventArgs
        {
            p_event += new GenericEventHandler<TSender, TEventArgs>(p_handler);
        }
    }
}

GenericEventHandler

using System;

namespace Common
{
    [SerializableAttribute]
    public delegate void GenericEventHandler<TSender, TEventArgs>
        (TSender sender, TEventArgs e)
        where TEventArgs : EventArgs;
}

ICommunicationsModel

using System;
using Common;
using MachineControl.OPC;

namespace InspectionStation.Models
{
    public interface ICommunicationsModel
    {
        event GenericEventHandler<Tag, EventArgs>
            When_Communications_Pulses_Heartbeat;
    }
}

ICommunicationsView

namespace InspectionStation.Views
{
    public interface ICommunicationsView
    {
        bool Set_Communications_Status_Indicator { set; }
    }
}

2 ответа

Решение

Поскольку компилятор C# строго требует, чтобы за событиями, используемыми вне класса, следовал += или же -=, команды присоединения и отсоединения для обработчиков, будет невозможно расширить и использовать это за пределами класса.

Однако, если вы хотите создать более конкретные методы для самого класса, например:

object.RespondWhenSomethingChangesBy(DoingThisOtherThing);

тогда внутри этого метода вы можете использовать метод расширения, потому что этот класс определил событие. Я знаю, это означает, что вы будете создавать много кода для событий, но если это то, что вы действительно хотите, то вышеупомянутое может оказаться еще более упорядоченным, чем:

object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);

Я полностью понимаю вашу позицию здесь и надеюсь, что Microsoft решит, что события будут расширяться в будущем (я могу подумать о некоторых интересных причинах, по которым я буду ее использовать), но до тех пор, я думаю, нам просто придется обойти это. Это. Честно говоря, я уверен, что есть несколько очень веских причин, по которым он не был реализован в первую очередь, Microsoft довольно хорошо продумывает эти вещи.

Учитывая ответ Mike Perrenoud, я решил сделать следующее как часть моей схемы...

    public class CommuncationsStatusPresenter
    {
        ...

        private void HookEvents()
        {
            m_model.
                When_Communications_Pulses_Heartbeat += new EventHandler<Tag, EventArgs>(
                Set_the_state_of_an_Indicator);
        }

        // Eventhandler
        void Set_the_state_of_an_Indicator(Tag sender, EventArgs e)
        {
            ...
        }
    }
}

В этом нет ничего особенного... просто согласованное автоматическое форматирование, основанное на новых строках, но, кажется, лучшее решение на данный момент (то есть. Я могу почти прочитать код вслух, чтобы быстро определить его намерения, не прибегая к обширным закомментированным описаниям).

Примечание: я переименовал длинный GenericEventHandler просто EventHandler так как особого имени не нужно.

Другие вопросы по тегам