传递一个数组

时间:2015-12-11 19:40:53

标签: c# generics

在下面的示例代码中,当我不包含class约束

时,为什么对genric类型的ArrayMethod调用失败?
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) { }
}

2 个答案:

答案 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[]的子类型。