我想动态地发现和注册接口实现。为了便于讨论,我有两个类似的方法:
public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent
public void Register<TEvent>(Action<TEvent> action) where TEvent : IEvent
{
Register<TEvent>(handler.Handle);
}
接口如下:
public interface IHandler<T> where T : IEvent
{
void Handle(T args);
}
public interface IEvent
{
}
然后我有具体的实现,如:
public class ChangedEvent : IEvent
{...}
public class ChangedHandler : IHandler<ChangedEvent>
{
public void Handle(ChangedEvent args)
{
}
}
我可以在我的程序集中发现IHandler<>的所有具体实现,我想做这样的事情:
IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
object instance = Activator.CreateInstance(type);
Listeners.Register((IHandler<IEvent>)instance);
}
代码可以编译,它不是无效的,但是在运行时强制转换失败,因为它是无效的。但是,如果我转换为一个具体的事件,比如:
IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
object instance = Activator.CreateInstance(type);
Listeners.Register((IHandler<ChangedEvent>)instance);
}
此强制转换是有效的,并且将运行。问题是场景的动态性,我希望能够发现类型并注册它们。我不想为处理程序创建非泛型接口,但我认为这是一个不可能的场景,因为框架没有足够的信息来推断所需的类型。有什么方法可以做到这一点,或者你有什么建议来达到预期的结果吗?
许多谢谢。由于协方差和逆变性的原因,这不起作用,想象它起作用了,并且您做了以下操作。
public class AnotherTypeOfEvent : IEvent {...}
public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent
{
//Really our runtime type expects ChangedEvent, but our constraint is
//only for IEvent so you could do this - oh dear..
handler.Handle(new AnotherTypeOfEvent());
}
Listeners.Register((IHandler<IEvent>)new ChangedHandler());
您将把AnotherTypeOfEvent
传递到您的ChangedHandler.Handle
方法中,该方法显然期望ChangedEvent
,这将导致各种问题。
为什么不在typefinder中指定您想要获得的类型,因为您将在之后强制转换它?
IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<IEvent>));
foreach (Type type in types)
{
object instance = Activator.CreateInstance(type);
Listeners.Register((IHandler<IEvent>)instance);
}
我不知道你得到了什么错误。我可以很好地编译:
public interface IEvent
{
}
public interface IHandler<T>
{
}
public class Test //: ITest
{
public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent
{
}
}
public class ChangedEvent : IEvent
{
}
public class Example
{
public static void Main()
{
Test t = new Test();
Type[] types = new Type[10];
foreach (Type type in types)
{
object instance = Activator.CreateInstance(type);
t.Register((IHandler<IEvent>)instance);
}
}
}