2

我正在开发一个处理事件的系统:

public interface IEvent { ..}
public class CreateUserEvent : IEvent {...}
public class ChangeUserNameEvent : IEvent {...}

每个事件都有一个特定的处理程序

public interface IEventHandler<T> where T : IEvent { Handle(T @event); }
public class CreateUserEventHandler : IEventHandler<CreateUserEvent> { ... }
public class ChangeUserNameEventHandler : IEventHandler<ChangeUserNameEvent> {...}

到目前为止,一切都非常简单。但是,我想为正确的事件创建使用正确事件处理程序的类。

到目前为止,我想出了以下方法:

Dictionary<Type, object> EventHandlers; // stores all registered event handlers

// Note that at compile time I do not exactly know the specialization of IEvent 
// so I cannot give HandleEvent a generic type parameter :(
void HandleEvent(IEvent @event)
 {
    // inspect the type of the event handler at runtime
    // the event also needs to be dynamic. Even though we know its a
    // specialization of IEvent that is compatible with 
    // the handlers .Handle method
    var handler = EventHandlers[@event.GetType()] as dynamic;       
    hanler.Handle(@event as dynamic);
}

这个解决方案有效,但我必须使用两种动态类型,这让我很担心。我想我可能做出了错误的设计决定,但我想不出其他架构/模式可以摆脱这些动态。

所以我的问题归结为:如何选择和使用具有通用性且运行时自省最少的接口的正确实现?

注意我更喜欢 IEvent 和 IEventHandler 实现完全不知道这个过程的解决方案

4

1 回答 1

1

我会根据 Rx.NET 中的Subject<T>和 OfType 扩展方法松散地尝试一些东西。这会将类型检查延迟到最后一刻,因此您可能希望将其重写为基于字典的解决方案。此外,此代码绝不是线程安全的,请使用 Rx.NET 代码作为参考,以在多线程使用案例中改进它。

这个解决方案最大的问题是处理程序的类型隐藏在对 EventDispatcher.Dispatch 方法的调用中。在问题中,您声明您想要一个非泛型方法,该方法没有关于要调度的事件的编译时知识。

public interface IEvent
{   
}

public interface IEventHandler<TEvent> where TEvent: IEvent
{
    void Handle<TEvent>(TEvent message)
}

public class EventDispatcher
{
    private List<object> handlers = new List<object>();

    public void Dispatch<TEvent>(TEvent message)
    {
        foreach (var handler in handlers)
        {
            if (handler is IEventHandler<TEvent>)
            {
                var safeHandler = (IEventHandler<TEvent>)handler;
                safeHandler.Handle(message);
            }
        }
    }

    public IDisposable Register<TEvent>(IEventHandler<TEvent> handler)
    {
        this.handlers.Add(handler);
        return new Subscription(this, handler);
    }

    class Subscription : IDisposable
    {
        private EventDispatcher dispatcher;
        private IEventHandler<TEvent> handler;

        public Subscription(EventDispatcher dispatcher, IEventHandler<TEvent> handler)
        {
            this.dispatcher = dispatcher;
            this.handler = handler;
        }

        public void Dispose()
        {
            if (dispatcher == null)
                return;

            dispatcher.Unsubscribe(handler);
            dispatcher = null;
        }
    }

    private void Unsubscribe(IEventHandler<TEvent> handler)
    {
        this.handlers.Remove(handler);
    }
}
于 2015-07-22T08:36:28.523 回答