C#params object []奇怪的行为 [英] C# params object[] strange behavior

查看:241
本文介绍了C#params object []奇怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑此代码

 命名空间ConsoleApplication1 
{
class Program
{
static void Main(string [] args)
{
string [] strings = new string [] {Test1,Test2,Test3};

int [] ints = new int [] {1,2,3,4};

测试(字符串);

Test(ints);
}

public static void Test(params object [] objects)
{
}
}
}

此页面





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

解决方案


这是未定义的行为吗?


没有。这是按设计行为。




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

否。所有版本的C#都有这种行为。



这是C#的一些有趣规则的冲突的后果。



<第一个相关规则是:具有params数组的方法可以以正常或扩展形式调用。正常形式好像没有params。扩展形式接受param并将它们捆绑到一个自动生成的数组中。 如果两种表单都适用,则正常表单赢得扩展表单



现在,这似乎很明智;如果你有一个对象数组,你想传递对象数组,而不是包含对象数组的数组。



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



第二个含义是:由于把那个乌龟放入真正的字符串数组必须抛出,这意味着每次您将某些内容放入基本类型的数组中,运行时必须验证类型检查。因此,在每次写入时,C#中的数组写入都是非常昂贵的,因此可以捕获到少量的坏写入。



混乱,这就是为什么不安全的数组协方差在我的不幸的C#功能的列表。



这两个规则的组合解释了你的观察。字符串数组可以转换为对象数组,因此该方法适用于正常形式。



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



另请参见:



为什么params的行为如此?



您的问题可能与以下内容重复:




Considering this code

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)
        {
        }
    }
}

And this page https://msdn.microsoft.com/fr-ca/library/w5zay9db.aspx

I would expect (params object[] objects) to be an array of one element with a string[] as the first element, but when I debug, I see that (params object[] objects) is { "Test1", "Test2", "Test3" }.

However, with an int[], I get an object[] with int[] as first element.

Is this undefined behavior? Does that depend on the .Net framework version / Mono version?

解决方案

Nice find!

Is this undefined behavior?

No. This is by-design behaviour. Weird design, but by design.

Does that depend on the .Net framework version / Mono version?

No. All versions of C# have this behaviour.

This is a consequence of the collision of some interesting rules of C#.

The first relevant rule is: a method with a params array may be called in either "normal" or "expanded" form. Normal form is as if there was no "params". Expanded form takes the params and bundles them up into an array that is automatically generated. If both forms are applicable then normal form wins over expanded form.

Now, that perhaps seems sensible; if you have an array of objects in hand, odds are good that you want to pass the array of objects, not an array that contains an array of objects.

The second relevant rule is that C# allows unsafe array covariance when the element type is a reference type. That is, an array of strings may be converted to an array of objects implicitly. You'll note that this has two implications. First, it means that when you have an array of objects, it might actually be an array of strings, so putting, say, a turtle into that array of objects might cause a type error. This is very surprising! You expect that every array of objects can take any object, but that is not true in C#. Some arrays of objects are lying.

The second implication is: since putting that turtle into what is really an array of strings must throw, it means that every time you put something into an array of base type, the runtime must verify that the types check. So array writes are extra expensive in C# on every write, so that the vanishingly small minority of bad writes can be caught.

This is a mess, and this is why unsafe array covariance tops my list of unfortunate C# features.

The combination of these two rules explains your observations. The array of strings is convertible to an array of objects, and therefore the method is applicable in normal form.

For the array of ints, well, covariance does not apply to value types. So the array of ints is not convertible to an array of objects, so the method is not applicable in its normal form. But an array of ints is an object, so it is applicable in expanded form.

See also:

Why does params behave like this?

Your question is arguably a duplicate of:

Is there a way to distingish myFunc(1, 2, 3) from myFunc(new int[] { 1, 2, 3 })?

这篇关于C#params object []奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆