【问题标题】:Why .NET 4 variance for generic type arguments not also for classes? [duplicate]为什么泛型类型参数的 .NET 4 差异不适用于类? [复制]
【发布时间】:2011-04-18 17:21:20
【问题描述】:

可能的重复:
Why isn't there generic variance for classes in C# 4.0?
Why does C# (4.0) not allow co- and contravariance in generic class types?

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

【问题讨论】:

  • 不确定你在说什么,类支持协变和逆变:见这篇博文:blogs.msdn.com/b/wriju/archive/2009/07/31/…
  • 那篇文章只是显示了代表的差异。
  • 谁投票结束为“不是一个真正的问题”?这是一个非常好的问题......
  • 是的! :) 实际上 Stackoverflow 是一个完整的问题,人们试图将新的方差内容应用于类(自然而然地失败了)。
  • @Thomas:是的,我有。方差不是黑魔法,这个概念自几个世纪以来就被很好地理解,并且已经被证明可以工作数十次。事实上,通过方差和更好的编译器,可以在编译时检测到错误,而这会导致之前在运行时出现未检测到的错误。因此,对真实方差的支持可以使程序更正确。 .NET 方法与 Java 中的泛型类似。我很生气,没有哪个主流 VM 不采用“让我们一起破解”的方法来进行类型系统设计。

标签: c#-4.0 covariance contravariance


【解决方案1】:

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

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

您是否愿意再等 6 个月 .net 才能获得这种支持?


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

  • 接口 / 委托——用于模拟应用程序的概念类型系统
  • 用于实现上述类型
  • 类继承用于在执行上述操作时减少代码重复
  • 协变和逆变是关于应用程序的概念类型系统

【讨论】:

    【解决方案2】:

    为了类型安全,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 实现的最简单的情况也会带来挑战 - 首先如何将源数据放入实例中?

    【讨论】:

    • 在构造函数中接受 T 类型的参数但没有其他实例方法的类类型,并且具有返回类型为 T 的方法,理论上可以在 T 中协变而没有任何类型安全问题。困难来自静态变量。如果类 Thing&lt;T&gt; 具有 int 类型的公共静态字段 Foo,则 Thing&lt;BaseType&gt; 将具有与 Thing&lt;DerivedType&gt; 不同的 Foo
    猜你喜欢
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多