C#params object 奇怪的行为

考虑这个代码

namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string[] strings = new string[] { "Test1", "Test2", "Test3" }; int[] ints = new int[] { 1, 2, 3, 4 }; Test(strings); Test(ints); } public static void Test(params object[] objects) { } } } 

这个页面https://msdn.microsoft.com/fr-ca/library/w5zay9db.aspx

我希望(params object []对象)是一个元素的数组,以字符串[]作为第一个元素,但是当我调试时,我看到(params object []对象)是{“Test1”,“Test2” “,”Test3“}。

但是,使用int [],我得到一个object [],其中int []作为第一个元素。

用字符串

有了整数

这是未定义的行为吗? 这取决于.Net框架版本/ Mono版本吗?

很好找!

这是未定义的行为吗?

不。这是设计行为。 奇怪的设计,但设计。

这取决于.Net框架版本/ Mono版本吗?

不会。所有版本的C#都有此行为。

这是一些有趣的C#规则碰撞的结果。

第一个相关规则是:具有params数组的方法可以以“正常”或“扩展”forms调用。 正常forms就好像没有“参数”。 扩展forms使用参数并将它们捆绑成一个自动生成的数组。 如果两种forms都适用,则普通forms胜过扩展forms

现在,这似乎是明智的; 如果你手头有一个对象数组,那么想要传递对象数组的几率是好的,而不是包含对象数组的数组。

第二个相关规则是当元素类型是引用类型时 ,C#允许不安全的数组协方差 。 也就是说,字符串数组可以隐式地转换为对象数组。 你会注意到这有两个含义。 首先,这意味着当你有一个对象数组时,它实际上可能是一个字符串数组,所以将乌龟放入该对象数组可能会导致类型错误。 这非常令人惊讶! 您希望每个对象数组都可以接受任何对象,但在C#中则不然。 一些物体arrays正在撒谎。

第二个含义是:由于将该乌龟放入真正的字符串数组必须抛出,这意味着每次将某些东西放入基类型数组中时,运行时必须validation类型是否检查 。 因此,在每次写入时,C#中的数组写入都是非常昂贵的,因此可以捕获极少数不良写入。

这是一个烂摊子,这就是为什么不安全的数组协方差在我不幸的C#function列表中名列前茅的原因。

这两个规则的组合解释了您的观察结果。 字符串数组可以转换为对象数组,因此该方法适用于普通forms。

对于整数数组,协方差不适用于值类型。 因此,int数组不能转换为对象数组,因此该方法不适用于其正常forms。 但是一组int是一个对象,因此它适用于扩展forms。

也可以看看:

为什么params表现得像这样?

您的问题可以说是重复的:

有没有办法从myFunc(new int [] {1,2,3}}中删除myFunc(1,2,3)?

我不是专家,但params关键字的想法是使能够对方法进行不同的调用,而不管你有多少元素。

 Test(object1) Test(object1, object2) Test(object1,..., objectN) 

所以你所看到的是正常行为并不奇怪。 有关此链接的更多信息

通过使用params关键字,您可以指定采用可变数量参数的方法参数。

您可以发送以逗号分隔的参数列表,这些参数包含在参数声明中指定的类型或指定类型的参数数组中。 你也可以不发送任何参数。 如果不发送参数,则参数列表的长度为零。

在方法声明中的params关键字之后不允许使用其他参数,并且在方法声明中只允许使用一个params关键字。

 public static void Test(params string[] strings) { } Test(string1) Test(string1, string2) 

等等string1 … stringN。