C#params object []奇怪的行为

evg*_*sa3 19 c# arrays casting params

考虑这个代码

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)
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

用字符串

有了整数

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

Eri*_*ert 27

很好找!

这是未定义的行为吗?

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

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

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

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

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

现在,这似乎是明智的; 如果您手头有一个对象数组,那么您希望传递对象数组,而不是包含对象数组的数组的几率很高.

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

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

这是一个烂摊子,这就是为什么不安全的数组协方差排在我不幸的C#特性列表之上.

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

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

也可以看看:

为什么params表现得像这样?

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

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

  • @ evg02gsa3:正确.其中T是引用类型的所有`T []`都可以转换为`object []`,但该协方差仅适用于引用类型.如果你有引用类型`Animal`和`Giraffe`然后`长颈鹿[]`可转换为动物`[]`,`但INT []`不转换为`值类型[]`或`对象[]`. (2认同)

mjs*_*jsr 5

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

Test(object1)
Test(object1, object2)
Test(object1,..., objectN)
Run Code Online (Sandbox Code Playgroud)

所以你所看到的是正常行为并不奇怪.在这个环节更多信息MSDN

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

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

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