【问题标题】:C# casting with generic interfaces使用泛型接口进行 C# 转换
【发布时间】:2014-10-09 12:26:22
【问题描述】:

我试图了解为什么在这种情况下投射不起作用。

假设以下接口:

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

我正在使用 Autofac 来解析基于事件的处理程序列表,这很好,但它当然会完全具体地创建它们,在运行时我需要通过接口处理它们。我可以很容易地使用反射来调用句柄方法,但看起来这应该可以工作:/

【问题讨论】:

  • 尝试在界面声明中将 T 标记为out。这看起来像是一个协方差问题。
  • 是的,试试谷歌搜索 covariancecontravariance
  • @BradleyDotNET 那么接口定义将无法编译。它是一个内在的逆变 API。
  • @BradleyDotNET 不应该是in吗?
  • @TimothyShields 是的,该接口在概念上是逆变的,而不是协变的,但随后他试图在协变庄园中使用它,因此即使进行了更改,使用 sill 也不起作用。

标签: c# generics interface casting


【解决方案1】:

您不能在概念上将IHandler&lt;SomeEvent&gt; 视为IHandler&lt;IDomainEvent&gt;IHandler&lt;IDomainEvent&gt; 需要能够接受AThirdEvent 的实例(实现IDomainEvent)作为Handle 的参数,但您的SomeEventHandler 类型不能接受AThirdEvent 实例,只有SomeEvent实例。

编译器正确地通知您,从概念的角度来看,这种类型转换是无效的。

从概念上讲,您的界面实际上是逆变的。如果你有一个IHandler&lt;IDomainEvent&gt;,你可以将它隐式转换为IHandler&lt;SomeEvent&gt;(如果你调整了接口的定义以通知编译器它实际上是逆变的)因为如果你的Handle方法可以接受任何类型的@ 987654333@ 那么显然它可以接受每一个SomeEvent

【讨论】:

  • 谢谢大家的帮助。第一段虽然实际上让它在我脑海中点击。
【解决方案2】:

这需要您的interface to be covariant

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

但是,您的界面本身不支持这一点,因为它实际上是逆变的。允许它工作不会是类型安全的,并且没有直接的解决方法。协变接口只允许返回T,不接受T作为方法的参数。

详情请见variance in generic interfaces

【讨论】:

  • 但是接口在其 API 中不是协变的,它是逆变的。
  • 我确实尝试过,但后来出现了这个错误:无效方差:类型参数“T”必须在“Testing.IHandler.Handle(T)”上逆变有效。 “T”是协变的。
  • @RyanLM 是的,因为你的接口在概念上不是协变的,所以这个不应该是有效的,不是编译器告诉你你原本有效的程序是无效的。跨度>
  • @RyanLM 我更新以提供详细信息 - 在我编写它时没有详细查看您尝试做的事情。基本上,你不能这样做:p
  • @Servy 已更新以包含这一点 - 很懒 - 感谢您指出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2023-01-11
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多