Mono + именованные / необязательные параметры = ошибка компилятора? - PullRequest
0 голосов
/ 21 декабря 2010

Я столкнулся с некоторыми непредвиденными последствиями перехода на моно 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

Удаление использования необязательного / именованного параметра (то есть вызова нового Person (1.0, null, «John Doe») или нового Person (1.0, null, name: «John Doe»),or new Person (1.0, «Джон Доу»)) приводит к безупречной компиляции.Кроме того, под VS2010 файл (и все решение, с которого я начал) компилируется нормально.Приведение удаляет ошибку CS0266, но не CS0584 - так что нет ничего удивительного.

Мой вопрос: это я что-то делаю не так, или MCS (т.е. ошибка в MCS очевидна для меня - что еще, внутренняя ошибка'' означало бы, но, возможно, это нормально, такая программа не будет компилироваться), или, возможно, компилятор Microsoft в VS2010 не должен позволять компилировать такой код?

Могу поспорить, что mcs не прав (не может угадать правильный конструктор), но, может быть, это иное, и я не должен знать лучше?

PS.Я попытался найти известную ошибку в Google и Novell Bugzilla, но не смог найти ничего подходящего.Опять же, я могу быть слепым;)

Ответы [ 2 ]

3 голосов
/ 21 декабря 2010

Хорошо, здесь идет.Сбой действительно из-за третьей перегрузки, 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 голосов
/ 14 апреля 2013

Для других, приходящих в эту тему. Эта ошибка все еще существует в последних версиях Mono Compiler на апрель 2013 года. Я создал обходной путь без необходимости изменять компилятор, используя перегруженные функции C #.

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

Foo(int a, bool b, string c)
...