为什么C#不支持变体泛型类? [英] Why doesn't C# support variant generic classes?

查看:150
本文介绍了为什么C#不支持变体泛型类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以这个小的LINQPad为例:

  void Main()
{
Foo< object> foo = new Foo< string>();
Console.WriteLine(foo.Get());
}

class Foo< out T>
{
public T Get()
{
return default(T);


无法编译这个错误:


方差修改器无效。只有接口和委托类型参数可以指定为变体。


我没有看到代码的任何逻辑问题。一切都可以静态验证。为什么这是不允许的?它会导致语言的不一致,还是由于CLR的限制而导致实施成本太高?如果是后者,我应该作为开发人员知道这个限制吗?



考虑到接口支持它,我期望类支持从逻辑上遵循。

解决方案

其中一个原因是:

  class Foo< out T> 
{
T _store;
public T Get()
{
_store = default(T);
return _store;






这个类包含一个不是协变的特征,因为它有一个字段,可以将字段设置为值。它是以协变方式使用的,因为它只被赋予默认值,并且对于实际使用协方差的任何情况,它只会是 null 。 / p>

现在还不清楚我们是否可以允许。不允许它会刺激用户(它毕竟符合你建议的相同潜在规则),但允许它很困难(分析已经变得稍微棘手,我们甚至没有开始寻找真正棘手的情况)。 / p>

另一方面,对此的分析要简单得多:

  void Main()
{
IFoo< object> foo = new Foo< string>();
Console.WriteLine(foo.Get());
}

interface IFoo< out T>
{
T Get();
}

class Foo< T> :IFoo< T>
{
T _store;
public T Get()
{
_store = default(T);
return _store;






$ b

很容易确定没有任何 IFoo< T> 打破了协方差,因为它没有得到。所有必要的是确保没有使用 T 作为参数(包括setter方法的参数)并完成。



由于类似的原因,潜在的限制在类上比在界面上要困难得多,这也降低了协变类有用的程度。它们当然不会是无用的,但是平衡指定和实现有关允许执行什么规则的工作量是多么有用,远远低于协变接口的有用程度的平衡以及指定和实施它们的工作量。



当然,差距足以说明它已经超越了好吧,如果你打算允许X这将是愚蠢的,不允许Y ...。

Take this small LINQPad example:

void Main()
{
    Foo<object> foo = new Foo<string>();
    Console.WriteLine(foo.Get());
}

class Foo<out T>
{
    public T Get()
    {
        return default(T);
    }
}

It fails to compile with this error:

Invalid variance modifier. Only interface and delegate type parameters can be specified as variant.

I don't see any logical problem with the code. Everything can be statically verified. Why is this not allowed? Would it cause some inconsistency in the language, or was it deemed too expensive to implement due to a limitation in the CLR? If it is the latter, what should I as a developer know about said limitation?

Considering that interfaces support it, I would have expected class support to logically follow from that.

解决方案

One reason would be:

class Foo<out T>
{
  T _store;
  public T Get()
  {
    _store = default(T);
    return _store;
  }
}

This class contains a feature that is not covariant, because it has a field, and fields can be set to values. It is though used in a covariant way, because it is only ever assigned the default value and that is only ever going to be null for any case where covariance is actually used.

As such it's not clear if we could allow it. Not allowing it would irritate users (it does after all match the same potential rules you suggest), but allowing it is difficult (the analysis has gotten slightly tricky already and we're not that even beginning to hunt for really tricky cases).

On the other hand, the analysis of this is much simpler:

void Main()
{
  IFoo<object> foo = new Foo<string>();
  Console.WriteLine(foo.Get());
}

interface IFoo<out T>
{
  T Get();
}

class Foo<T> : IFoo<T>
{
  T _store;
  public T Get()
  {
    _store = default(T);
    return _store;
  }
}

It's easy to determine that none of the implementation of IFoo<T> breaks the covariance, because it hasn't got any. All that's necessary is to make sure that there is no use of T as a parameter (including that of a setter method) and it's done.

The fact that the potential restriction is a lot more arduous on a class than on an interface for similar reasons, also reduces the degree to which covariant classes would be useful. They certainly wouldn't be useless, but the balance of how useful they would be over how much work it would be to specify and implement the rules about what they would be allowed to do is much less than the balance of how useful covariant interfaces are over how over how much work it was to specify and implement them.

Certainly, the difference is enough that it's past the point of "well, if you're going to allow X it would be silly to not allow Y…".

这篇关于为什么C#不支持变体泛型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆