动态通用接口转换

发布于 2024-10-31 01:13:24 字数 1425 浏览 1 评论 0原文

我想动态发现并注册接口实现。为了便于论证,我有两种与此类似的方法:

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

代码将编译,它不是无效的,但在运行时转换失败,因为它是无效的。 但是,如果我转换为具体的 IEvent,例如:

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<ChangedEvent>)instance);
}

此转换是有效的,并且它将运行。问题是场景的动态,我希望能够发现类型并注册它们。 我不想为处理程序创建非通用接口,但我相信这是不可能的场景,因为框架没有足够的信息来推断所需的类型。 有什么方法可以实现这一点,或者您有什么建议来实现预期的结果吗?

非常感谢。

I want to dynamically discover and register interface implementations. For the sake of argument I have two methods similar to these:

public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent

public void Register<TEvent>(Action<TEvent> action) where TEvent : IEvent
{
    Register<TEvent>(handler.Handle);
}

And the interfaces are like the following:

public interface IHandler<T> where T : IEvent
{
    void Handle(T args);
}

public interface IEvent
{
}

Then I have the concrete implementations like:

public class ChangedEvent : IEvent
{...}

public class ChangedHandler : IHandler<ChangedEvent>
{
    public void Handle(ChangedEvent args)
    {

    }
}

I can then discover all concrete implementations of IHandler<> in my assemblies, and I wanted to do something like this:

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<IEvent>)instance);
}

The code will compile, it's not invalid, but in run time the cast fails because it's invalid.
However, if I cast to a concrete IEvent like:

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<ChangedEvent>)instance);
}

This cast is valid, and it will run. The problem is the dynamic of the scenario, I want to be able to discover the types and register them.
I didn't want to create a non-generic interface for the handler, but I believe this is an impossible scenario because the framework doesn't have enough information to infer the required types.
Is there any way to achieve this, or do you have any sugestions to achieve the desired result?

Many thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

养猫人 2024-11-07 01:13:24

这不起作用,因为 协变和逆变,想象一下这有效并且您执行了以下操作。

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,这会导致各种问题。

This doesn't work because of Covariance and contravariance, imagine this worked and you did the following.

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

You would be passing AnotherTypeOfEvent into you ChangedHandler.Handle method, which clearly expects ChangedEvent, this would cause all sorts of problems.

む无字情书 2024-11-07 01:13:24

为什么不在 typefinder 中指定您想要获取的类型,因为您将在之后对其进行强制转换?

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<IEvent>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<IEvent>)instance);
}

Why don't you specify in typefinder the type that you want to get, as you will cast it after ?

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<IEvent>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<IEvent>)instance);
}
贱贱哒 2024-11-07 01:13:24

我不确定你遇到了什么错误。这对我来说编译得很好:

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

I am not sure what error you are getting. This compiles fine for me:

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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文