这是C#4中的协变错误吗?

在下面baseElements代码中,我希望能够隐式地从elements转换为baseElements因为TBase可以隐式转换为IBase

 public interface IBase { } public interface IDerived : IBase { } public class VarianceBug { public void Foo<TBase>() where TBase : IBase { IEnumerable<TBase> elements = null; IEnumerable<IDerived> derivedElements = null; IEnumerable<IBase> baseElements; // works fine baseElements = derivedElements; // error CS0266: Cannot implicitly convert type // 'System.Collections.Generic.IEnumerable<TBase>' to // 'System.Collections.Generic.IEnumerable<IBase>'. // An explicit conversion exists (are you missing a cast?) baseElements = elements; } } 

但是,我收到了评论中提到的错误。

引用规范:

如果T是用variablestypes参数T<X1, …, Xn>声明的接口或委托types,则typesT<A1, …, An>可以方差转换为T<B1, …, Bn>并且对于每个变体types参数Xi ,下列之一成立:

  • Xi是协变的,并且存在从AiBi的隐式参考或身份转换

  • Xi是逆变的,并存在着从BiAi的隐含的参照或身份转换

  • Xi是不变的,从AiBi存在一个身份转换

检查我的代码,看起来与规范一致:

  • IEnumerable<out T>是一个接口types

  • IEnumerable<out T>用variablestypes参数声明

  • T是协变的

  • 存在从TBaseIBase的隐式参考转换

那么 – 这是C#4编译器中的一个错误吗?

差异仅适用于参考types(或者存在标识转换)。 不知道TBase是引用types,除非你添加: class

  public void Foo<TBase>() where TBase : class, IBase 

因为我可以写一个:

 public struct Evil : IBase {} 

马克是正确的 – 我正要贴上相同的回应。

请参阅协变和逆变常见问题解答:

http://blogs.msdn.com/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

从常见问题解答:

“仅当types参数是引用types时才支持差异”。

值types不支持差异

以下不编译:

 // int is a value type, so the code doesn't compile. IEnumerable<Object> objects = new List<int>(); // Compiler error here.