C# 混凝土子类的通用工厂

C# 混凝土子类的通用工厂,c#,generics,polymorphism,factory,covariance,C#,Generics,Polymorphism,Factory,Covariance,考虑以下代码: public interface IEventHandler<in T> where T : IEvent { void Execute(T @event); } 公共接口IEventHandler,其中T:IEvent { 无效执行(T@事件); } 对于这些处理程序,我实现了一些具体的处理程序子类: public class SomeEventHandler : IEventHandler<SomeEvent> { public v

考虑以下代码:

public interface IEventHandler<in T> where T : IEvent
{
    void Execute(T @event);
}
公共接口IEventHandler,其中T:IEvent
{
无效执行(T@事件);
}
对于这些处理程序,我实现了一些具体的处理程序子类:

public class SomeEventHandler : IEventHandler<SomeEvent>
{
    public void Execute(SomeEvent @event) { /* ... */ }
}
公共类SomeEventHandler:IEventHandler
{
public void Execute(SomeEvent@event){/*…*/}
}
现在我有了一个工厂来检索事件的相应处理程序:

public class EventHandlerFactory : IEventHandlerFactory
{
    public IEventHandler<T> Create<T>(T @event) where T : IEvent
    {
        // What to do in here?
    }
}
公共类EventHandlerFactory:IEventHandlerFactory
{
公共IEventHandler创建(T@event),其中T:IEvent
{
//在这里干什么?
}
}
我试图检查事件的类型,然后返回相应的处理程序,但类型系统当然拒绝:

if(@event is SomeEvent)
{
    return (IEventHandler<T>) new SomeEventHandler();
}
if(@event是SomeEvent)
{
返回(IEventHandler)新的SomeEventHandler();
}
我不会这么做,但我想知道如何允许代码使与
Create
的接口成为可能

编辑:当我循环遍历可枚举的事件时,T被视为IEvent,因此类型系统将抛出异常:

var events = IEnumarable<IEvent>() { /* ... */ };

foreach (var @event in events)
{
    var eventHandler = eventHandlerFactory.Create(@event);
}
var events=IEnumarable(){/*…*/};
foreach(事件中的var@event)
{
var eventHandler=eventHandlerFactory.Create(@event);
}

Create(T@event)
-方法将抛出异常,因为T是一个IEvent而不是具体类型。我可以用
(动态)@event
解决它,但这不是我真正想要做的。

经典的工厂模式。
我喜欢做的事情如下:

public class EventHandlerFactory : IEventHandlerFactory
{
    private readonly Dictionary<Type, Type> _eventHandlers = new Dictionary<Type, Type>();

    public EventHandlerFactory()
    {
        //add a mapping between the type, and the handler
        //note - this could be done with reflection to automate this
        _eventHandlers.Add(typeof(SomeEvent), typeof(SomeEventHandler));
    }

    public IEventHandler<T> Create<T>(T @event) where T : IEvent
    {
        var handler = _eventHandlers[typeof(T)];

        if (handler != null)
        {
            //now use Activator.CreateInstance to instantiate the type
            return (IEventHandler<T>)Activator.CreateInstance(handler);
        }

        throw new Exception("Handler not found");
    }
}
公共类EventHandlerFactory:IEventHandlerFactory
{
私有只读词典_eventHandlers=new Dictionary();
公共事件HandlerFactory()
{
//在类型和处理程序之间添加映射
//注意-这可以通过反射来实现,从而实现自动化
_Add(typeof(SomeEvent),typeof(SomeEventHandler));
}
公共IEventHandler创建(T@event),其中T:IEvent
{
var handler=_eventHandlers[typeof(T)];
if(处理程序!=null)
{
//现在使用Activator.CreateInstance实例化该类型
return(IEventHandler)Activator.CreateInstance(handler);
}
抛出新异常(“未找到处理程序”);
}
}
替代解决方案:

如果要避免反射或IEventHandler实现没有默认构造函数:

public interface IEventHandler
{
}

public interface IEventHandler<in T> : IEventHandler where T : IEvent
{
    void Execute(T @event);
}

public class EventHandlerFactory
{
    private static readonly Dictionary<Type, Func<IEventHandler>> _eventHandlers = new Dictionary<Type, Func<IEventHandler>>
    {
        { typeof(SomeEvent), () => new SomeEventHandler() }
    };

    public IEventHandler<T> Create<T>(T @event) where T : IEvent
    {
        Func<IEventHandler> handler;
        if (_eventHandlers.TryGetValue(typeof(T), out handler))
        {
            return (IEventHandler<T>)handler();
        }

        throw new Exception("Handler not found");
    }
}
公共接口IEventHandler
{
}
公共接口IEventHandler:IEventHandler其中T:IEvent
{
无效执行(T@事件);
}
公共类EventHandlerFactory
{
私有静态只读字典_eventHandlers=新字典
{
{typeof(SomeEvent),()=>newsomeeventhandler()}
};
公共IEventHandler创建(T@event),其中T:IEvent
{
Func处理器;
if(_eventHandlers.TryGetValue(typeof(T),out handler))
{
返回(IEventHandler)处理程序();
}
抛出新异常(“未找到处理程序”);
}
}

创建此事件的内容可能重复-
events=IEnumarable()
-注释掉的代码中有什么内容?
IEvent
s从何而来这是我将如何做的,尽管可能有一些小的调整。例如,作为一个静态类可能更好。也可以考虑抛出一个异常而不是返回NULL。没有像我通常通过IOC容器处理它那样使它显式静态化。我把我的实例化为<代码> IEventHandlerFactory <代码>一个实例,这是保持它非静态的一个很好的理由。@亚历克斯谢谢你的回答。不幸的是,我面临着另一个(可能相关的)问题。我循环通过一个IEnumerable从工厂获取相应的处理程序;因为我这样做,T总是IEEvent,而不是具体的SomeEvent类型,所以会抛出InvalidCastException,因为这些类型不匹配。我不确定我是否理解。。你能编辑你的问题来显示代码吗?