【发布时间】:2010-05-06 17:49:05
【问题描述】:
在下面的代码中,我希望能够从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是使用变体类型参数T<X1, …, Xn>声明的接口或委托类型,则类型T<A1, …, An>可以变型转换为类型T<B1, …, Bn>,并且对于每个变体类型参数Xi一个以下持有:
Xi是协变的,存在从Ai到Bi的隐式引用或身份转换
Xi是逆变的,存在从Bi到Ai的隐式引用或身份转换
Xi是不变的,存在从Ai到Bi的身份转换
检查我的代码,它似乎与规范一致:
-
IEnumerable<out T>是一个接口类型 -
IEnumerable<out T>使用变体类型参数声明 -
T是协变的 -
存在从
TBase到IBase的隐式引用转换
那么 - 这是 C# 4 编译器中的错误吗?
【问题讨论】:
-
当你显式转换时会发生什么?编译器说有一个。既然你在低调,这有点道理..?
-
只是为了明确说明 - 这是你的最后一个项目符号“存在从 TBase 到 IBase 的隐式引用转换”这是不真实的(除非你添加
: class)。它可能是可分配的,但它不一定是引用转换。没有: class,它是一个“受约束的”转换,这是一种神奇的方式,可以让相同的 IL 以相同的方式在引用类型和值类型上调用方法(包括属性访问器):msdn.microsoft.com/en-us/library/… -
Charles:你错了 - 第一个作业有效(Works on My Machine (TM))。
-
马克:对——我的错。它不是引用类型,所以没有引用转换。但是我留下了一个问题,为什么第一个作业有效?
标签: c# generics covariance