使用泛型接口的c#强制转换
本文关键字:转换 泛型接口 | 更新日期: 2023-09-27 18:18:24
我试图理解为什么在这种情况下铸造不工作。
假设以下接口:
public interface IDomainEvent { }
public interface IHandler<T> where T: IDomainEvent
{
void Handle(T args);
}
和这些简单的实现:
public class SomeEvent : IDomainEvent
{
public string Value { get; set; }
}
public class SomeEventHandler : IHandler<SomeEvent>
{
public void Handle(SomeEvent args) { }
}
我不明白为什么我不能做这个强制转换:
var handler = new SomeEventHandler() as IHandler<IDomainEvent>;
我正在使用autofacc来解析基于事件的处理程序列表,它做得很好,但是它创建它们当然是完全具体的,在运行时我需要通过接口来处理它们。我可以很容易地使用反射来调用句柄方法,但似乎应该这样做:/
你不能在概念上将IHandler<SomeEvent>
视为IHandler<IDomainEvent>
。IHandler<IDomainEvent>
需要能够接受AThirdEvent
的实例(实现IDomainEvent
)作为Handle
的参数,但是您的SomeEventHandler
类型不能接受AThirdEvent
实例,只能接受SomeEvent
实例。
编译器正确地告诉你,从概念的角度来看,这种类型转换是无效的。
从概念上讲,你的接口实际上是逆变的。如果你有一个IHandler<IDomainEvent>
,你可以隐式地将它转换为IHandler<SomeEvent>
(如果你调整接口的定义,告知编译器它实际上是逆变的),因为如果你的Handle
方法可以接受任何类型的IDomainEvent
,那么显然它可以接受每一个SomeEvent
。
这要求你的接口是协变的。
public interface IHandler<out T> : where T : IDomainEvent
然而,你的接口本身不支持这个,因为它实际上是逆变的。允许它工作将不是类型安全的,并且没有直接的解决方法。协变接口只允许返回T
,不接受T
作为方法的参数。