C#params明显的编译器bug(C#5.0)
这是我认为昨天解决的一个post的后续内容。 昨天我在以下情况下遇到了我的代码问题:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication3 { class Program { class Bar { int v; public Bar(int v) { this.v = v; } public override string ToString() { return v.ToString(); } } static void Main(string[] args) { Foo(1, 2, 3); Foo(new int[] { 1, 2, 3 }); Foo(new Bar(1), new Bar(2), new Bar(3)); Foo(new Bar[] { new Bar(1), new Bar(2), new Bar(3) }); System.Threading.Thread.Sleep(20000); } static void Foo(params object[] objs) { Console.WriteLine("New call to Foo: "); foreach(object o in objs) Console.WriteLine("Type = " + o.GetType() + ", value = "+o.ToString()); } } }
如果你运行它,你可以看到上次调用Foo时出现问题。 参数是向量的事实是“丢失”的。
那么….有谁知道如何报告C#编译器错误? 或者这会被视为reflection错误?
(真是令人宽慰:我很沮丧地认为我浪费了时间来处理我自己的错误。实际上它毕竟是一个C#错误,而且我得到了certificate!我们经常看到实际的C#编译器错误这几天?不常见……)
我希望这两个调用function相同 – params参数是被调用方法中的数组。 Jon Skeet在上一个问题中的示例有效,因为int的数组与对象数组不协变(因此被视为new Object[] { new Int[] {1,2,3} }
),但在此示例中FooBars数组与对象数组协变,因此您的参数将扩展为objs
参数。
所有事物的维基百科涵盖了这个确切的案例: 协方差和逆变(计算机科学)
抱歉,但我确信这不是编译器错误。
编辑:
你可以实现你想要的:
Foo(new Object[] { new Bar[] { new Bar(1), new Bar(2), new Bar(3) } });
NEW EDIT(其他作者):
或者只是使用:
Foo((Object)new Bar[] { new Bar(1), new Bar(2), new Bar(3) });
C#4.0规范非常清楚这一切是如何发挥作用的。 7.5.3.1表示如果具有params
的函数可以以正常forms(忽略params
关键字)或扩展forms(使用params
关键字)应用,则普通forms获胜。
假设Foo
被声明为Foo(params object[] args)
,则调用Foo(new Foobar[] {new Foobar(1), new Foobar(2), new Foobar(3)) });
适用于正常forms,因为Foobar[]
可隐式转换为object[]
(6.1.6第5条)。 因此,使用常规forms并忽略扩展forms。
(我假设C#5.0没有改变这部分语言。)
请参阅C#规范的7.5.3.1节:
7.5.3.1适用的function成员
当满足以下所有条件时,函数成员被称为关于参数列表A的适用函数成员:
对于包含参数数组的函数成员,如果函数成员适用于上述规则,则称其适用于其正常forms。 如果包含参数数组的函数成员不适用于其正常forms,则函数成员可能适用于其扩展forms[。]
因为您传递的数组可以隐式转换为object[]
,并且因为重载解析比“扩展”forms更喜欢“普通”forms,所以您观察到的行为符合规范,并且没有错误。
除了Chris Shain描述的解决方法之外,您还可以将Bar
从类更改为结构; 这使得数组不再可以隐式转换为object[]
,因此您将获得所需的行为。
我相信你错了Ken那是因为int []不是object []类型,所以编译器假定int []只是传递给方法的参数之一。
这是如何做:
new Foobar[] { } is object[]; // true new int[] { } is object[]; // false
更新:您可以使方法通用,让编译器知道struct / object类型传递为params:
void Foo(params T[] objs) { foreach (T o in objs) Console.WriteLine(o.GetType()); }
所以我建议最好的答案是我是对的,这确实是一个编译器错误。 虽然我清楚地看到了这一点,但您的解释忽略了“params”关键字。 事实上,要以这种方式使用协方差,必须忽略params关键字,就好像它不重要一样。 我假设没有合理的解释来编译代码这种方式,Params作为Foo类型签名上的关键字出现:要调用你的解释,你需要说服我myClass []应该与object []类型匹配但是,鉴于params构造,我们甚至不应该问这个问题。 实际上,您对此的想法越多,它就越清楚它实际上是一个真正的C#5.0编译器错误:编译器忽略了应用params关键字。 语言规范实际上根本不需要任何改变。 我应该得到某种奇怪的徽章,imho!
上述就是C#学习教程:C#params明显的编译器bug(C#5.0)分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/942294.html