使用错误的Console.WriteLine重载的int[]

9
我是一名有用的助手,可以为您翻译文本。
我和同事一起做一些基础的C#教程时,遇到了一个我们认为很有趣的难题。
以下代码按预期工作:
string[] strings = { "1", "2", "3" };
Console.WriteLine("{0}, {1}, {2}", strings);

它获取字符串数组并使用 Console.WriteLine(string format, params object[] arg) 方法的重载将字符串 "1, 2, 3" 打印到控制台。

然而,以下代码无法正常工作:

int[] ints = { 1, 2, 3 };
Console.WriteLine("{0}, {1}, {2}", ints);

您会收到一个格式异常(FormatException),其中包含消息:索引(从零开始)必须大于或等于零,且小于参数列表的大小。 使用 IntelliSense,可以看到它正在尝试使用 Console.WriteLine(string format, object arg0) 重载,这就是为什么我们会收到该消息的原因,它没有将 ints 视为数组,尽管显然它确实是一个数组。
如果我们切换到更明显的方式:
int[] ints = { 1, 2, 3 };
Console.WriteLine("{0},{1},{2}", ints[0], ints[1], ints[2]);

它再次工作并再次使用params object[]重载。

为什么该方法无法将int[]视为数组? Int32是一个结构体是否有所不同?如果是这样,为什么?

编辑

我进行了一个快速测试,测试了相同格式的双精度浮点数,但它们也不能正常工作,这使我认为确实是类型是结构体的事实,但我仍然不明白为什么会有所不同。


7
存在隐式转换 string[] -> object[]。但是对于 int[] -> object[],不存在这样的转换。是因为 int 是值类型。 - user4003407
阅读此文 - Hamid Pourjam
可能是Casting int[] to object[]的重复问题。 - Hamid Pourjam
2个回答

8

这个方法适用于 string 类型的对象,是因为 C# 的 数组协变性(Array Covariance) 特性。

对于任意两个引用类型 AB,如果存在从 AB 的隐式或显式引用转换,则也存在从数组类型 A[] 到数组类型 B[] 的相同引用转换。

string 可以隐式转换为 object,所以 WriteLine 方法可以将你的 string[] 数组作为 object[] 数组传入。

int[] 没有协变性,因为 int 不是引用类型。如果需要使用显式转换,可以像这样:

object[] ints = (new int[]{ 1,2,3 }).Cast<object>().ToArray();
Console.WriteLine("{0}, {1}, {2}", ints);       

Demo.


或者只需使用 object[] ints = { 1, 2, 3 }; - Patryk Spytkowski
@ PatrykSpytkowski 好吧,这个想法是展示如何从原始数组开始,最终得到一个对象数组,但是是的,您的语法显然更简洁。 - Sergey Kalinichenko

5

是的,这是因为int是值类型。它试图找到最佳匹配。 string[]可以转换为object[],但是int[]不能转换,因为结构体数组不是协变的。作为解决方法,您可以使用

int[] ints = { 1, 2, 3 };
Console.WriteLine("{0}, {1}, {2}", ints.Cast<Object>().ToArray());

更准确地说,int[] 是一个数组类型(数组类型是引用类型),其元素类型 int 是一个值类型。当元素类型是值类型时,数组协变性将不起作用,因此 int[] 不能转换为 object[] - Jeppe Stig Nielsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接