3

可能的重复:
为什么 C# 4.0 中的类没有通用差异?
为什么 C# (4.0) 不允许泛型类类型中的协变和逆变?

新的 .NET 4.0 通用类型参数的协变和逆变只适用于接口和委托。不支持课程的原因是什么?

4

2 回答 2

8

为了类型安全,C# 4.0 仅对标有inout的类型参数支持协变/逆变。

如果这扩展到类,您还必须用 in 我们的 out 标记类型参数,这最终会受到非常严格的限制。这很可能是 CLR 的设计者选择不允许它的原因。例如,考虑以下类:

public class Stack<T>
{
  int position;
  T[] data = new T[100];
  public void Push (T obj)   { data[position++] = obj;  }
  public T Pop()             { return data[--position]; }
}

在我们的输出中将 T 注释为 any 是不可能的,因为 T 用于输入和输出位置。因此,此类永远不会协变或逆变 - 即使在 C# 支持的类的协变/逆变类型参数中也是如此。

接口很好地解决了这个问题。我们可以如下定义两个接口,并让 Stack 实现两者:

public interface IPoppable<out T> { T Pop(); }
public interface IPushable<in T> { void Push (T obj); }

请注意,T 对于 IPoppable 是协变的,对于 IPushable 是逆变的。这意味着 T 可以是协变的或逆变的 - 取决于您是转换为 IPoppable 还是 IPushable。

协变/逆变对类的使用有限的另一个原因是它会排除使用类型参数作为字段 - 因为字段有效地允许输入和输出操作。事实上,如果类型参数标记为 in 或 out,很难编写一个完全有用的类。即使是编写协变 Enumerable 实现的最简单的情况也会带来挑战——您如何将源数据放入实例中?

于 2010-09-29T09:26:40.723 回答
1

.NET 团队以及 C# 和 VB.NET 团队资源有限,他们在协变和逆变方面所做的工作解决了大多数现实世界的问题。类型系统的正确性非常复杂——如果在其他情况下导致不安全的代码,那么在 99.9999% 的情况下工作的解决方案就不够好。

我不认为在类方法上支持协变和逆变规范(例如“in”/“out”)的成本/时间具有足够大的价值。由于缺少多重类继承,我可以看到很少有情况可以使用它们。

您宁愿再等 6 个月的 .net 以获得这种支持吗?


另一种思考方式是在 .net 中

  • 接口/委托——用于对应用程序的概念类型系统进行建模
  • 用于实现上述类型
  • 在进行上述操作时,使用类继承来减少代码重复
  • 协变和逆变是关于应用程序的概念类型系统
于 2010-09-29T09:53:33.300 回答