在下面的示例代码中,当我不包含class
约束
public interface IFoo { }
public interface IBar : IFoo { }
public class Test
{
public void ClassConstraintTest<T>() where T : class, IFoo
{
T[] variable = new T[0];
ArrayMethod(variable);
}
public void GenericTest<T>() where T : IFoo
{
T[] variable = new T[0];
ArrayMethod(variable); // Compilation error: Can't convert T[] to IFoo[]
}
public void InheritanceTest()
{
IBar[] variable = new IBar[0];
ArrayMethod(variable);
}
public void ArrayMethod(IFoo[] args) { }
}
答案 0 :(得分:9)
这是因为array covariance,即MySubtype[]
是MyType[]
的子类型的事实,仅适用于参考类型。 class
约束确保T
是引用类型。
(请注意,回想起来,数组协方差为considered to be a bad idea。如果可以,例如,通过使ArrayMethod
通用或改为使用IEnumerable<IFoo>
,请尽量避免使用它。)< / p>
答案 1 :(得分:5)
简而言之:只有当两个数组都是引用(class
)类型时,数组协方差才有效。
要理解这一点,您必须了解不同类型数组的内存布局。在C#中,我们有值数组(int[]
,float[]
,DateTime[]
,任何用户定义的struct[]
),其中每个事物顺序存储在数组中,并且引用数组({ {1}},object[]
,任何用户定义的string[]
,class[]
或interface[]
),其中引用按顺序存储在数组中,对象存储在数组外部只要它们适合记忆。
当您请求该方法适用于任何delegate[]
(没有T
约束)时,您允许这两种类型的数组中的任何一种,但编译器知道任何{{1 (或任何其他值数组)不会以某种方式神奇地成为有效的: class
(或任何其他参考数组)并禁止转换。即使您的结构实现int[]
而没有其他原因,IFoo[]
是参考数组而IFoo
将是一个值数组,也会发生这种情况。
但是,当您指定IFoo[]
是引用类型(即T[]
声明)时,T
现在可能是有效的class
,因为它们都是参考数组。因此,编译器允许使用数组协方差规则的代码(声明您可以使用T[]
,其中IFoo[]
是必需的,因为T[]
是IFoo[]
的子类型。