2010-12-20 50 views
0

我遇到了一些无法预料的移植到mono 2.8.1的后果。问题可以被归结为一个示例程序(I一直无法进一步降低它,切割几个类和〜1000行的代码下面引用该文件之后)单声道+命名/可选参数=编译器错误?

public class Person 
{ 
    public Person(int age, string name = null){} 
    public Person(double income, string name = null){} 
    public Person(double income, int age, string name = null){} 
} 

class Program 
{ 
    static void Main() 
    { 
     Person p = new Person(1.0, name: "John Doe"); 
    } 
} 

编译的上面的代码与MCS给出输出:

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 

取出使用可选/命名参数(即调用新的Person(1.0,空, “李四”)或新的Person(1.0,空,名称: “李四”),或新的Person( 1.0,“John Doe”))导致了完美的编译。此外,在VS2010下,文件(以及我开始的整个解决方案)编译得很好。 Casting会移除错误CS0266,但不会移除CS0584 - 因此在那里不会感到意外。我的问题:是我做错了什么,或者mcs(即mcs中的bug对我来说很明显 - 还有什么,内部错误会是什么意思,但也许没关系,这样的程序不会编译),或者也许在VS2010中的微软编译器不应该让这样的代码编译?

我敢打赌,这是MCS谁的错(不能猜对构造函数),但也许它,否则,我不应该知道的?

PS。我尝试在Google和Novell的Bugzilla中搜索这样一个已知的bug,但无法找到任何相关的东西。再一次,我可能会失明;)

+0

你甚至可以设置一个字符串为空... – Blam 2010-12-20 23:55:23

+0

有没有错误编译使用visual studio。我没有单声道来尝试它,以确认。 – 2010-12-21 00:05:54

+0

@Courtney:单声道可在线获取[此处](http://ideone.com/kZ2Eo)。 – Vlad 2010-12-21 00:07:11

回答

3

好的,这里有。事故的确是由于第三次超载,Person(double income, int age, string name = 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); 
           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; 
+0

你的答案是否也适用于mono-2.8.1?我不知道你是否知道它的确如此,并默默地假设或者你错过了我使用2.8.1的事实? AFAIR 2.6.7完全支持命名/可选参数,但我不知道代码本身是否改变... – triazotan 2010-12-21 01:48:55

+0

不知道。由于两个版本都出现同样的崩溃,我认为这也适用于2.8.1。但是,我在这里只有2.6.7,所以我无法测试。 – Jester 2010-12-21 01:56:10

0

对于其他人来此线程。该错误仍然存​​在于截至2013年4月的最新版本的Mono Compiler中。我创建了一个解决方案,无需使用C#重载函数修改编译器。

Foo(int a, bool b = true) { 
    Foo(a, b, "Default String"); 
} 

Foo(int a, bool b, string c)