我正在处理一个处理事件的系统:
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实现完全不知道此过程的解决方案
答案 0 :(得分: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);
}
}