订阅/取消订阅(添加/删除)扩展方法内的事件

时间:2013-04-12 02:33:44

标签: c# events c#-4.0 extension-methods presenter-first

我想创建一个流畅的扩展方法来订阅(并且不太重要的是取消订阅)一个事件。这是使用.RespondBy(Method)代替+= new Eventhandler(Method)

的扩展程序

我想这样做:object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);

而不是:object.WhenSomethingChanges += new EventHandler(DoingThisOtherThing);

我做了一堆谷歌搜索,虽然我没有完全掌握错综复杂的细节,但我现在明白这与您是否正在访问本地领域或公共活动有关。

话虽如此,我只是对“如何”这样做感兴趣,而不关心“为什么”我的第一次尝试没有奏效。失败的解决方法,至少是一个明确的“ 你根本不能这样做...... ”也是有用的信息......

CommuncationsStatusPresenter (Image)

Image of attempted usage, does not compile

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 个答案:

答案 0 :(得分:1)

因为C#编译器严格要求在类之外使用的事件必须后跟+=-=,对于处理程序的附加和分离命令,它赢了“可以扩展并在课堂外使用

但是,如果您愿意在类本身上构建更具体的方法,例如:

object.RespondWhenSomethingChangesBy(DoingThisOtherThing);

然后你可以在该方法内部利用扩展方法,因为该类定义了事件。我知道这意味着你要为事件构建大量的锅炉板代码,但如果这是你真正想要的,那么前面提到的可能会比以下更精简:

object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);

我完全理解你在这里的立场,并希望微软选择允许在未来扩展事件(我可以想到一些有趣的原因,我会用它),但在那之前,我想我们只会有解决它。老实说,我确信有一些非常好的理由它首先没有实现,微软在思考这些方面做得很好。

答案 1 :(得分:1)

鉴于Michael 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,因为不需要特殊名称。