gpt4 book ai didi

c# - 根据另一个对象的类型选择/使用具有通用参数的接口(interface)的实现

转载 作者:太空宇宙 更新时间:2023-11-03 13:03:40 25 4
gpt4 key购买 nike

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

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);
}

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

所以我的问题归结为:我如何选择和使用具有泛型的接口(interface)的正确实现,同时最少的运行时自省(introspection)?

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

最佳答案

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

此解决方案的最大问题是处理程序的类型隐藏在对 EventDispatcher.Dispatch 方法的调用中。在问题中,您声明您想要一个非泛型方法,该方法没有关于要分派(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);
}
}

关于c# - 根据另一个对象的类型选择/使用具有通用参数的接口(interface)的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31527042/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com