无法将值类型数组转换为params对象[]

时间:2012-02-01 22:22:47

标签: c# .net

如果C#可以将int转换为对象,为什么不将int []转换为对象[]?

简单程序示例:

void Main()
{
    var a = new String[]{"0", "1"};
    var b = new int[]{0, 1};

    AssertMoreThan1(a); // No Exception
    AssertMoreThan1(b); // Exception
}

static void AssertMoreThan1(params object[] v){
    if(v.Length == 1){
        throw new Exception("Too Few Parameters");
    }
}

2 个答案:

答案 0 :(得分:49)

  

如果C#可以将int转换为对象,为什么不将int []转换为对象[]?

你的问题也可以说是“C#中数组转换的协方差规则是什么?”

它们有点棘手,并以几种有趣和不幸的方式打破。

首先,我们应该明确说明“协方差”的含义。协方差是映射保留关系的属性。这里的映射是“T转到T的数组”。 关系是“可以隐式转换”。例如:

Giraffe可以隐式转换为Mammal

这是两种类型之间的关系。现在将映射应用于关系的两端:

Giraffe[]可以转换为Mammal[]

如果第一个语句的真实性总是需要第二个语句的真实性 - 也就是说,如果映射保留关系的真实性 - 那么映射被称为“协变” ”。

作为简写,不是说“从T到T的数组的映射是隐式转换关系的协变映射”,我们只是说“数组是协变的”,并希望其余部分从上下文中理解。

好了,现在我们已经定义了下来:带有引用类型元素的数组在C#中是协变的。可悲的是,这是一个破坏的协方差:

class Mammal {}
class Giraffe : Mammal {}
class Tiger : Mammal {}
...
Mammal[] mammals = new Giraffe[1];  

这是完全合法的,因为引用类型元素的数组在C#中是协变的。但是这会在运行时崩溃:

mammals[0] = new Tiger();

因为哺乳动物真的是一群长颈鹿

这意味着每次到其元素为未密封的引用类型的数组时,运行时执行类型检查,如果类型检查可能会崩溃失败

这是我“C#最糟糕的功能”的候选人,但实际上工作

您的问题是“当源数组是值类型的数组且目标数组是引用类型的数组时,为什么数组协方差不起作用?”

因为这两件事在运行时有不同的形式。假设您有一个包含十个元素的byte[]。为数组元素保留的实际存储长度为十个字节。假设您使用的是64位计算机,并且您拥有包含10个元素的object[]。存储空间大八倍!

显然,您不能将通过引用转换对存储的引用转换为十个字节到存储,以便对字节进行十次八字节引用。额外的七十个字节不会冒出来;有人必须分配它们。

此外:谁做拳击?如果你有一个包含十个对象的数组,并且每个对象都是一个字节,那么这些字节中的每一个都是盒装。但是字节数组中的字节不是盒装的。那么当你进行转换时,谁来做拳击?

通常在C#中,协变转换始终保留表示。 “动物参考”的表示与“长颈鹿参考”的表示完全相同。但是“int”和“对象的引用”的表示完全不同。

一个人希望将一个数组类型转换为另一个数组类型不会分配和复制一个巨大的数组。但是我们不能在十个字节的数组和一个包含十个引用的八十个字节的数组之间使用引用标识,因此整个事情就变得非法了。

现在,您可能会说,当表达式与值类型相同时会发生什么?事实上,这在C#中是非法的:

int[] x = new uint[10];

因为在C#中规则是只有仅涉及引用类型的协变数组转换才是合法的。但是如果你强迫它由运行时完成:

int[] x = (int[])(object) new uint[10];

然后运行时允许它,因为四字节int和四字节uint具有相同的表示。

如果你想更好地理解这一点,那么你应该阅读我关于协方差和逆变在C#中如何运作的整篇系列文章:

答案 1 :(得分:8)

确实,你无法转换它。参考类型数组是协变的;值类型数组不是。所以;你将不得不使用以下之一:

一组盒装值:

var b = new object[] {0,1};

可以使用IList

static void AssertMoreThan1(IList v) {
   ... (check with .Count)
}

或泛型:

static void AssertMoreThan1<T>(T[] v) {
   ...
}

最后一个是我的偏好。