为什么C#(4.0)不允许泛型类的共同和逆变?

Lar*_*sen 22 c# generics covariance contravariance c#-4.0

这种限制的真正原因是什么?这只是必须完成的工作吗?概念上难吗?这不可能吗?

当然,人们不能在字段中使用类型参数,因为它们总是读写.但这不是答案,可以吗?

这个问题的原因是我在C#4上写了一篇关于方差支持的文章,我觉得我应该解释为什么它仅限于委托和接口.只是为了逆转举证责任.

更新: 埃里克问了一个例子.

怎么样(不知道这是否有意义,但是:-))

public class Lookup<out T> where T : Animal {
  public T Find(string name) {
    Animal a = _cache.FindAnimalByName(name);
    return a as T;
  }
}

var findReptiles = new Lookup<Reptile>();
Lookup<Animal> findAnimals = findReptiles;
Run Code Online (Sandbox Code Playgroud)

在一个类中拥有它的原因可能是类本身中保存的缓存.请不要将您的不同类型的宠物命名为相同!

顺便说一句,这让我想到了C#5.0中的可选类型参数 :-)

更新2:我没有声称CLR和C#应该允许这个.只是想了解是什么原因导致它没有.

Eri*_*ert 20

首先,正如Tomas所说,CLR不支持它.

第二,这将如何运作?假设你有

class C<out T>
{ ... how are you planning on using T in here? ... }
Run Code Online (Sandbox Code Playgroud)

T只能用于输出位置.如您所知,该类不能包含任何类型为T的字段,因为该字段可以写入.该类不能有任何采用T的方法,因为它们是逻辑写入的.假设您有此功能 - 您将如何利用它?

如果我们可以让一个类型为T的只读字段合法,那么这对于不可变类很有用.这样我们就可以大大减少不正确写入的可能性.但是很难想出其他允许以类型安全方式变化的场景.

如果你有这样的场景,我很乐意看到它.这将指向有朝一日在CLR中实现这一点.

更新:见

为什么C#4.0中的类没有通用方差?

关于这个问题的更多信息.

  • 另一个用例是幻像类型,其中T仅用于类型安全而不用于类的实现. (3认同)
  • Lazy <T>和Task <T>类是否适合在T上协变?他们只在公共API的out位置使用T. (2认同)

Tom*_*cek 8

据我所知,CLR不支持此功能,因此添加此功能也需要在CLR端进行大量工作.我相信在版本4.0之前CLR实际上支持接口和委托的共同和反向差异,因此这是一个相对简单的实现扩展.

(虽然支持这个类的功能绝对有用!)