C# 单声道+;命名/可选参数=编译器错误?
我在移植到mono 2.8.1时遇到了一些无法预料的后果。这个问题可以归结为一个示例程序(在将几个类和~1000行代码剪切到下面引用的文件后,我无法进一步减少它) 用mcs编译上述代码可得到以下输出:C# 单声道+;命名/可选参数=编译器错误?,c#,.net,c#-4.0,mono,C#,.net,C# 4.0,Mono,我在移植到mono 2.8.1时遇到了一些无法预料的后果。这个问题可以归结为一个示例程序(在将几个类和~1000行代码剪切到下面引用的文件后,我无法进一步减少它) 用mcs编译上述代码可得到以下输出: test.cs(22,24): error CS0584: Internal compiler error: Internal error test.cs(22,20): error CS0266: Cannot implicitly convert type `object' to `Named
test.cs(22,24): error CS0584: Internal compiler error: Internal error
test.cs(22,20): error CS0266: Cannot implicitly convert type `object' to `NamedParams.Person'.
An explicit conversion exists (are you missing a cast?)
Compilation failed: 2 error(s), 0 warnings
删除可选/命名参数(即调用new Person(1.0,null,“John Doe”)或new Person(1.0,null,name:“John Doe”)或new Person(1.0,John Doe))的使用将导致完美的编译。此外,在VS2010下,文件(以及我开始使用的整个解决方案)可以很好地编译。强制转换会删除错误CS0266,但不会删除CS0584——所以这并不奇怪
我的问题:是我做错了什么,还是mcs(即mcs中的错误对我来说是显而易见的——还有什么,内部错误“”可能意味着什么,但也许这样的程序不会编译没关系),或者VS2010中的Microsoft编译器不应该让这样的代码编译
我打赌是mcs错了(无法猜出正确的构造函数),但也许是其他原因,我不应该知道得更清楚
另外,我试着在Google和Novell的Bugzilla中搜索一个已知的bug,但是找不到任何相关的。再说一次,我可能是瞎子;) 好了,开始吧。这次崩溃确实是由于第三次过载,
Person(双倍收入,整数年龄,字符串名=null)
。
编译器发现您试图传递的参数少于签名中列出的参数,因此它会查找可选参数。它高兴地注意到,name
是可选的,并假设您没有传递该参数。它通过在提供的参数末尾附加一个占位符来实现这一点。接下来,它将对列表中的命名参数进行重新排序,以便它们最终位于正确的位置。这意味着John Doe
现在正确地位于name
的最后一个位置,但是占位符进入了age
位置。然后,编译器尝试填充默认值,但在没有默认值的位置发现占位符时感到震惊。它认为这不可能发生,因为占位符只是为可选参数添加的,现在突然不再是可选的了。由于不知道该做什么,它抛出了一个异常
以下修补程序似乎可以解决此问题(但可能会破坏其他功能,因此不提供保修):
——mono-2.6.7.orig/mcs/mcs/ecore.cs 2009-10-02 12:51:12.000000000+0200
+++mono-2.6.7/mcs/mcs/ecore.cs 2010-12-21 02:26:44.000000000+0100
@@ -3803,6 +3803,15 @@
int args_gap=Math.Abs(arg_count-param_count);
如果(可选_计数!=0){
+//重新调整作为命名参数传递的可选参数
+for(int i=0;i可选计数)
返回int.MaxValue-10000+参数间隔-可选计数;
供其他人使用。截至2013年4月,Mono编译器的最新版本中仍然存在该漏洞。我创建了一个变通方法,无需使用C#重载函数修改编译器
Foo(int a, bool b = true) {
Foo(a, b, "Default String");
}
Foo(int a, bool b, string c)
您甚至可以将字符串设置为null…使用visual studio编译此字符串时没有错误。但我没有mono来尝试确认。@Courtney:mono在线可用。mono 2.6.7在mono.CSharp.MethodGroupExpr.IsAppliebleSure中也会崩溃。在我看来,mono看起来像是一个mono bug。注意,mono也可以使用命名参数,但您有要删除最后一个重载(
个人(双倍收入,整数年龄,字符串名称=null)
重载)。显然Mono与重载解析混淆了,重载解析涉及在调用中使用可选参数和命名参数。或者其他。您的答案是否也适用于Mono-2.8.1?我不知道您是否知道,并且默默地假设,或者您忽略了我使用2.8.1的事实?AFAIR 2.6.7完全支持命名/可选参数,但我不知道代码本身是否已更改…不知道。由于两个版本显示相同的崩溃,我认为这也适用于2.8.1。但是,我这里只有2.6.7,因此无法测试。
--- mono-2.6.7.orig/mcs/mcs/ecore.cs 2009-10-02 12:51:12.000000000 +0200
+++ mono-2.6.7/mcs/mcs/ecore.cs 2010-12-21 02:26:44.000000000 +0100
@@ -3803,6 +3803,15 @@
int args_gap = Math.Abs (arg_count - param_count);
if (optional_count != 0) {
+ // readjust for optional arguments passed as named arguments
+ for (int i = 0; i < arguments.Count; i++) {
+ NamedArgument na = arguments[i] as NamedArgument;
+ if (na == null)
+ continue;
+ int index = pd.GetParameterIndexByName (na.Name.Value);
+ if (pd.FixedParameters[index].HasDefaultValue)
+ optional_count--;
+ }
if (args_gap > optional_count)
return int.MaxValue - 10000 + args_gap - optional_count;
Foo(int a, bool b = true) {
Foo(a, b, "Default String");
}
Foo(int a, bool b, string c)