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

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

问题描述

考虑这个代码

命名空间 ConsoleApplication1{课程计划{静态无效主(字符串 [] args){string[] strings = new string[] { "Test1", "Test2", "Test3" };int[] ints = new int[] { 1, 2, 3, 4 };测试(字符串);测试(整数);}公共静态无效测试(参数对象[]对象){}}}

还有这个页面

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

解决方案

不错的发现!

<块引用>

这是未定义的行为吗?

没有.这是设计行为.奇怪的设计,但设计如此.

<块引用>

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

没有.所有版本的 C# 都有这种行为.

这是一些有趣的 C# 规则冲突的结果.

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

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

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

第二个含义是:由于将海龟放入真正的字符串数组中必须抛出,这意味着每次将内容放入基本类型的数组时,运行时都必须验证类型是否检查.因此,在 C# 中,每次 写入数组的成本都非常高,因此可以捕获极少数的错误写入.

这是一团糟,这就是为什么不安全的数组协方差在我的不幸 C# 功能列表中名列前茅.

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

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

另见:

为什么参数会这样?>

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

有没有办法区分 myFunc(1, 2, 3) 和 myFunc(new int[] { 1, 2, 3 })?

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天全站免登陆