C# 传递数组
在下面的示例代码中,当我没有包含C# 传递数组,c#,generics,C#,Generics,在下面的示例代码中,当我没有包含类约束时,为什么对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]; Arra
类
约束时,为什么对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) { }
}
公共接口IFoo{}
公共接口IBar:IFoo{}
公开课考试
{
public void ClassConstraintTest(),其中T:class,IFoo
{
T[]变量=新T[0];
数组方法(变量);
}
public void GenericTest(),其中T:IFoo
{
T[]变量=新的T[0];
ArrayMethod(变量);//编译错误:无法将t[]转换为IFoo[]
}
公共无效继承测试()
{
IBar[]变量=新的IBar[0];
数组方法(变量);
}
公共空数组方法(IFoo[]args){}
}
这是因为,也就是说,MySubtype[]
是MyType[]
的一个子类型,只适用于引用类型。class
约束确保T
是引用类型
(请注意,回想起来,数组协方差是。如果可以,请尝试避免它,例如,将
ArrayMethod
设置为泛型,或者改用IEnumerable
。简而言之:数组协方差仅在两个数组都是引用(class
)类型时起作用
要理解这一点,您必须了解不同类型阵列的内存布局。在C#中,我们有值数组(int[]
,float[]
,DateTime[]
,任何用户定义的struct[]
),其中每个东西都顺序存储在数组中,还有引用数组(对象[]
,字符串[]
,任何用户定义的类[]
,接口[]
,或委托[]
),其中引用按顺序存储在数组内部,对象存储在数组外部的内存中
当您请求该方法在任何T
(没有:class
约束)上工作时,您允许这两种类型的数组中的任何一种,但编译器知道一个事实,即任何int[]
(或任何其他值数组)都不会以某种方式神奇地成为有效的IFoo[]
(或任何其他引用数组)并禁止转换。即使您的结构实现了IFoo
,除了IFoo[]
是一个引用数组,而T[]
将是一个值数组之外,也会发生这种情况
但是,当您指定
T
为引用类型(即class
声明)时,T[]
现在可能是有效的IFoo[]
,因为它们都是引用数组。因此,编译器允许代码使用数组协方差规则(您可以使用T[]
,其中IFoo[]
是必需的,因为T
是IFoo
的子类型)。一个好的类型系统应该有一个协方差类型,它可以用作数组,数组中的项可以读取、交换或复制。NET和Java中的数组类型可以作为此类类型以协变方式安全地使用,也可以作为可自由写入的集合以非协变方式安全地使用。也许对数组进行多种引用会更好,它们具有不同的广告功能,但是那些简单地说协变数组是一个“错误”的人并没有真正计算出替代方案的成本。