简体   繁体   English

使用通用接口进行C#转换

[英]C# casting with generic interfaces

I am trying to understand why casting does not work in this situation. 我试图理解为什么在这种情况下铸造不起作用。

Assume the following interfaces: 假设以下接口:

public interface IDomainEvent { }

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

And these simple implementations: 这些简单的实现:

public class SomeEvent : IDomainEvent
{
    public string Value { get; set; }
}

public class SomeEventHandler : IHandler<SomeEvent>
{
    public void Handle(SomeEvent args) { }
}

I do not understand why I cannot do this cast: 我不明白为什么我不能做这个演员:

var handler = new SomeEventHandler() as IHandler<IDomainEvent>;

I am using Autofac to resolve a list of handlers based on events, which it does fine, but it creates them of course fully concrete, which at runtime I need to handle them via interfaces. 我正在使用Autofac来解析基于事件的处理程序列表,它做得很好,但它创建它们当然是完全具体的,在运行时我需要通过接口处理它们。 I can use reflection easy enough to call the handle method, but it seems like this should work :/ 我可以使用反射很容易调用handle方法,但似乎这应该工作:/

You can't conceptually treat an IHandler<SomeEvent> as if it's an IHandler<IDomainEvent> . 您不能在概念IHandler<SomeEvent>视为IHandler<IDomainEvent> An IHandler<IDomainEvent> needs to be able to accept an instance of AThirdEvent (that implements IDomainEvent ) as a parameter to Handle , but your SomeEventHandler type can't accept AThirdEvent instances, only SomeEvent instances. IHandler<IDomainEvent>需要能够接受AThirdEvent (实现IDomainEvent )的实例作为Handle的参数,但是SomeEventHandler类型不能接受AThirdEvent实例,只能接受SomeEvent实例。

The compiler is correctly informing you that, from a conceptual perspective, this type conversion is not valid. 编译器正确地通知您,从概念的角度来看,此类型转换无效。

Conceptually your interface is actually contravariant . 从概念上讲,您的界面实际上是逆变的 If you had an IHandler<IDomainEvent> you could implicitly convert it to an IHandler<SomeEvent> (if you adjusted the definition of the interface to inform the compiler that it is in fact contravariant) because if your Handle method can accept any type of IDomainEvent then clearly it can accept every single SomeEvent . 如果您有一个IHandler<IDomainEvent>您可以隐式将其转换为IHandler<SomeEvent> (如果您调整了接口的定义以通知编译器它实际上是逆变的),因为如果您的Handle方法可以接受任何类型的IDomainEvent那么显然它可以接受每一个SomeEvent

This requires your interface to be covariant . 这要求您的界面是协变的

public interface IHandler<out T> : where T : IDomainEvent

However, your interface itself wouldn't support this, as it's effectively contravariant. 但是,您的界面本身不支持这一点,因为它有效地逆转。 Allowing this to work would not be type safe, and there is no direct workaround. 允许此工作不是类型安全的,并且没有直接的解决方法。 Covariant interfaces are only allowed to return T , not accept T as a parameter to a method. 协变接口只允许返回T ,不接受T作为方法的参数。

For details, see variance in generic interfaces . 有关详细信息,请参阅通用接口中的差异

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM