创建一个事件处理程序来处理多个事件类型

4

今天我在查看一些旧代码时发现一个事件处理程序,看起来像这样:

public void HandleEvent(EventClassA eventObj)
{
    if(eventObj is EventSubClassA)
    {
        HandleEventSubClassA(eventObj as EventSubClassA);
    }
    else if(eventObj is EventSubClassB)
    {
        HandleEventSubClassB(eventObj as EventSubClassB);
    }
    else if(eventObj.GetType() == typeof(EventSubClassC))
    {
        HandleEventSubClassC(eventObj as EventSubClassC);
    }
    else if(eventObj is EventSubClassD)
    {
        HandleEventSubClassD(eventObj as EventSubClassD);
    }
}

我认为这个看起来有点丑。所以我像这样重构了它:

delegate void EventHandler(dynamic eventObj);
private static readonly Dictionary<Type, EventHandler> EVENT_MAP = new Dictionary<Type, EventHandler>()
    {
        { typeof(EventSubClassA), HandleEventSubClassA },
        { typeof(EventSubClassB), HandleEventSubClassB },
        { typeof(EventSubClassC), HandleEventSubClassC },
        { typeof(EventSubClassD), HandleEventSubClassD }
    };

public void HandleEvent(EventClassA eventObj)
{
    EVENT_MAP[eventObj.GetType()](eventObj);
}

private void HandleEventSubClassA(dynamic evt)
{
    var eventObj = evt as EventSubClassA;
}

我请同事审查了这段代码,他对比之前的解决方案有所担忧。但我很难相信之前的解决方案是这种情况下最好的解决方案,因此我转向StackOverflow求助。

是否有更好的构建此类的方法?是否有我不知道的专门为此设计的模式?


3
数据类型 dynamic 的速度非常慢。将其装箱为 object 的速度更快。 - bash0r
似乎很简单,只需使用每个子类型调用它进行单元测试,看看会发生什么。 - D Stanley
我没有意识到dynamicobject之间有那种速度差异。谢谢。 - Chris
2个回答

3

您可以使用泛型使现有解决方案稍微更加安全:

private static Dictionary<Type, Delegate> handlers;

static HandlerClass()
{
    handlers = new Dictionary<Type, Delegate>();
    AddHandler<EventSubClassA>(HandleEventSubClassA);
    AddHandler<EventSubClassB>(HandleEventSubClassB);
    ...
}

public static void AddHandler<T>(Action<T> handler) where T : EventClassA
{
    handlers[typeof(T)] = handler;
}

public void HandleEvent(EventClassA @event)
{
    Delegate handler;
    if(handlers.TryGetValue(@event.GetType(), out handler))
    {
        handler.DynamicInvoke(@event);
    }
}

或者,如果您可以修改事件层次结构中的类,则可以实现访问者模式:

public interface IHandlers
{
    void HandleSubClassA(EventSubClassA a);
    void HandleSubClassB(EventSubClassB b);
    ...
}

public abstract class EventClassA
{
    public abstract void Visit(IHandlers handlers);
}

public class EventSubClassA : EventClassA
{
    public override void Visit(IHandlers handlers)
    {
        handlers.HandleSubClassA(this);
    }
}

1
我觉得我漏掉了什么。最好的方法不是为每种事件类型编写重载吗?

由于传入的参数已经被转换为基类:不,这在这里没有帮助。 - H H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接