【问题标题】:Generic event handling通用事件处理
【发布时间】:2012-01-07 23:07:54
【问题描述】:

我正在使用一些 .NET 框架,它允许注册 Action<IMessage> 类型的事件处理程序。

IMessage 是接收到的所有消息都在实现的接口。

我希望能够(以某种方式)注册知道接收到的具体消息类型的处理程序,以便更彻底地记录它。

类似的东西:

manager.Register(SpecialHandler);

public void SpecialHandler(SpecialMessage msg)
{
   // log.
}
  • SpecialMessage 是一种实现 IMessage 的类型。

这是不可能的,有没有简单的方法可以做到这一点?

【问题讨论】:

    标签: c# .net


    【解决方案1】:
    // improved version of Travis Gockel's approach
    void Register<T>(Action<T> action, bool invokeOnTypeMismatch = false)
        where T : IMessage
    {
        Action<IMessage> wrapped = (msg) =>
            {
                if (msg is T)
                {
                    action((T)msg);
                }
                else if (invokeOnTypeMismatch)
                {
                    action(default(T));
                }
            };
    
        // private Action<IMessage> method = delegate{};
        method += wrapped;
    }
    

    【讨论】:

      【解决方案2】:
      class MessageSystem
      {
          readonly Dictionary<Type, Action<IMessage>> handlers = new Dictionary<Type, Action<IMessage>>();
      
          public void Register<T>(Action<T> action) where T : IMessage
          {
              Action<IMessage> wrapped = (IMessage msg) => action((T)msg);
              handlers[typeof(T)] = wrapped;
          }
      
          public void Invoke(IMessage msg)
          {
              handlers[msg.GetType()](msg);
          }
      }
      

      【讨论】:

      • @Travis Gockel:这里的method 是什么?
      • 如果无法将 msg 强制转换为 T(即,如果注册了两个不同的专用处理程序),这将不起作用
      • @Tigran:好问题。我决定 Dictionary&lt;Type, Action&lt;IMessage&gt;&gt; 在这里更有意义。此外,应该有人考虑错误案例。
      • @TravisGockel 关于错误案例:我可以引导您注意我的答案吗?这应该可以解决问题。
      • @Tobias:这是一种可能的方式。但也许例外是这里处理错误情况的正确方法(您收到了一条您没想到的消息)。这真的取决于应用程序。另一个错误情况(在我的代码中)是如果您尝试使用相同的T 注册两次。我的寄存器只是覆盖了,但也许这也不好。
      【解决方案3】:

      这里可以使用多态

      元代码:

      interface IMessage 
      {
          void Handle()
          ... 
      }
      
      class MessageFoo : IMessage
      {
          void Handle()
          {
              //foo handle
          }
      }
      
      class MessageBar : IMessage
      {
          void Handle()
          {
              //bar handle
          }
      }
      

      这就是你处理它们的地方

      class HandlingManager
      {
          void HandleMessage(IMessage m)
          {
              m.Handle(); //knows which concrete type
          }
      }
      

      【讨论】:

      • 我喜欢这种方法,但问题是现在您的消息具有与其类型相关的行为。所以不可能以两种不同的方式处理同一条消息(取决于谁在处理它们)。
      • 我不拥有 IMessage 的代码,因此我不能以这种方式修改它。
      【解决方案4】:

      看看CSharpMessenger Extended

      这是一个基于委托的 C# 事件系统。它使用泛型来实现静态类型。与其他消息传递系统(例如 CSharpEventManager)一样,它允许在事件生产者和事件消费者之间进行消息传递,而无需生产者或消费者相互了解。 Messenger 被实现为静态类,因此永远不需要实例化 Messenger 对象。泛型的使用意味着参数可以是任何类型,并且不限于特殊 Message 类的子类 - 如果回调只需要一个浮点数,则为它提供一个浮点数。

      【讨论】:

        猜你喜欢
        • 2019-08-27
        • 1970-01-01
        • 1970-01-01
        • 2019-05-15
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 2014-11-22
        相关资源
        最近更新 更多