【问题标题】:Mono + named/optional parameters = compiler bug?Mono + 命名/可选参数 = 编译器错误?
【发布时间】:2010-12-20 23:51:46
【问题描述】:

我遇到了移植到单声道 2.8.1 的一些无法预料的后果。问题可以归结为一个示例程序(在将几个类和大约 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

删除使用可选/命名参数(即调用 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 中的错误对我来说很明显——还有什么 ,,internal error'' 是什么意思,但也许这样的程序不会编译没关系),或者也许VS2010中的微软编译器不应该让这样的代码编译?

我敢打赌是 mcs 错了(无法猜出正确的构造函数),但也许不是这样,我不应该知道得更好?

PS。我尝试在 Google 和 Novell 的 Bugzilla 中搜索类似的已知错误,但找不到任何相关内容。再说一次,我可能是盲人;)

【问题讨论】:

  • 你能设置一个字符串为空吗...
  • 使用 Visual Studio 编译这个没有错误。不过,我没有单声道来尝试确认。
  • @Courtney:Mono 可在线使用here
  • mono 2.6.7 在 Mono.CSharp.MethodGroupExpr.IsApplicable 中也崩溃
  • 在我看来确实像一个 Mono 错误。注意 Mono 也可以使用命名参数,但您必须删除最后一个重载(Person(double income, int age, string name = null) 重载)。显然,当调用中使用和命名参数时,Mono 对涉及可选参数的重载决议感到困惑。什么的。

标签: c# .net c#-4.0 mono


【解决方案1】:

好的,到此为止。崩溃确实是由于第三次过载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;

【讨论】:

  • 您的回答是否也适用于 mono-2.8.1?我不知道你是否知道它并默默地假设,或者你错过了我使用 2.8.1 的事实? AFAIR 2.6.7 完全支持命名/可选参数,但我不知道代码本身是否改变了......
  • 不知道。由于两个版本都表现出相同的崩溃,我认为这也适用于 2.8.1 是一个不错的选择。不过我这里只有2.6.7,所以无法测试。
【解决方案2】:

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

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

Foo(int a, bool b, string c)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多