为什么 .NET 4 对于泛型类型参数有差异,而对于类则不同?

发布于 2024-09-25 16:45:09 字数 419 浏览 0 评论 0原文

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

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

Possible Duplicates:
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?

The new .NET 4.0 co- and contravariance for generic type arguments only works for interfaces and delegates. What is the reason for not supporting it for classes too?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抱着落日 2024-10-02 16:45:09

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

如果这扩展到类,您还必须在 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 注释为任一,因为 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 实现的最简单的情况也会带来挑战 - 首先如何将源数据获取到实例中?

For type safety, C# 4.0 supports covariance/contravariance ONLY for type parameters marked with in or out.

If this extended to classes, you'd also have to mark type parameters with in our out and this would end up being very restrictive. This is most likely why the designers of the CLR chose not to allow it. For instance, consider the following class:

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

It would be impossible to annotate T as either in our out, because T is used in both input and output positions. Hence this class could never covariant or contravariant - even in C# supported covariance/contravariant type parameters for classes.

Interfaces solve the problem nicely. We can have define two interfaces as follows, and have Stack implement both:

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

Note that T is covariant for IPoppable and contravariant for IPushable. This means T can be either covariant or contravariant - depending on whether you cast to IPoppable or IPushable.

Another reason that covariance/contravariance would be of limited use with classes is it would rule out using type parameters as fields - because fields effectively allow both input and output operations. In fact, it would be hard to write a class that does anything useful at all with a type parameter marked as in or out. Even the simplest case of writing a covariant Enumerable implementation would present a challenge - how would you get source data into the instance to begin with?

夏日落 2024-10-02 16:45:09

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

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

您愿意再等 6 个月的 .net 来获得此支持吗?


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

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

The .NET team along with the C# and VB.NET team has limited resources, the work they have done on co- and contravariance solves most of the real world problem. Type systems are very complex to get right – a solution that works in 99.9999% of cases is not good enough if it leads to unsafe code in the other cases.

I don’t think the cost/time of supporting co- and contravariance specs (e.g. “in”/”out”) on class methods is of a great enough value. I can see very few cases when they would be useable – due to the lack of multiply class inheritance.

Would you rather had waited for another 6 months for .net so as to get this support?


Another way to think of this is that in .net

  • Interfaces / delegates – are used to model the conceptual type system of an application
  • Class are used to implement the above types
  • Class inheritance is used to reduce code duplication while doing the above
  • co- and contravariance is about the conceptual type system of an application
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文