Это ошибка?
Да.
Поздравляем, вы обнаружили ошибку в разрешении перегрузки. Ошибка воспроизводится в C # 4 и 5; не воспроизводится в версии семантического анализатора "Рослин". Я проинформировал команду тестирования C # 5, и, надеюсь, мы сможем исследовать эту проблему и решить ее до финального выпуска. (Как всегда, никаких обещаний.)
Далее следует правильный анализ. Кандидатами являются:
0: C(params string[]) in its normal form
1: C(params string[]) in its expanded form
2: C<string>(string)
3: C(string, object)
Нулевой кандидат явно неприменим, потому что string
не может быть преобразован в string[]
. Остается три.
Из трех мы должны определить единственный лучший метод. Мы делаем это путем попарного сравнения трех оставшихся кандидатов. Таких пар три. Все они имеют идентичные списки параметров после того, как мы удалим пропущенные необязательные параметры, что означает, что мы должны перейти к расширенному раунду разрешения конфликтов, описанному в разделе 7.5.3.2 спецификации.
Что лучше: 1 или 2? Уместное решение проблемы заключается в том, что универсальный метод всегда хуже, чем неуниверсальный. 2 хуже 1. Значит, 2 не может быть победителем.
Что лучше: 1 или 3? Соответствующее решение для разрешения конфликтов: метод, применимый только в его развернутой форме, всегда хуже, чем метод, применимый в его нормальной форме. Следовательно, 1 хуже 3. Значит, 1 не может быть победителем.
Что лучше, 2 или 3? Уместное решение проблемы заключается в том, что универсальный метод всегда хуже, чем неуниверсальный. 2 хуже 3. Итак, 2 не может быть победителем.
Чтобы быть выбранным из множества подходящих кандидатов, кандидат должен быть (1) непобежденным, (2) превзойти хотя бы одного другого кандидата и (3) быть уникальным кандидатом, который имеет первые два свойства. Кандидат номер три не побежден ни одним другим кандидатом, и побеждает по крайней мере еще одного кандидата; это единственный кандидат с этим свойством. Следовательно, третий кандидат - единственный лучший кандидат . Он должен победить.
Компилятор C # 4 не только ошибается, но, как вы правильно заметили, выдает странное сообщение об ошибке. Немного удивительно, что компилятор ошибается при анализе разрешения перегрузки. Совершенно неудивительно, что сообщение об ошибке выводится неправильно; эвристика ошибок «неоднозначного метода» в основном выбирает любые два метода из набора кандидатов, если лучший метод не может быть определен. Не очень хорошо находить «настоящую» двусмысленность, если она действительно существует.
Можно резонно спросить, почему это так. Довольно сложно найти два метода, которые были бы «однозначно неоднозначными», потому что отношение «лучшего» непереходно . Возможны ситуации, когда кандидат 1 лучше 2, 2 лучше 3 и 3 лучше 1. В таких ситуациях мы не можем добиться большего, чем выбрать два из них как «неоднозначные».
Я хотел бы улучшить эту эвристику для Roslyn, но это низкий приоритет.
(Упражнение для читателя: «Разработайте алгоритм линейного времени для определения уникального лучшего члена набора из n элементов, в котором отношение лучшего является непереходным», - вот один из вопросов, который мне задали в день собеседования с этой командой. Это не очень сложный алгоритм; попробуйте.)
Одной из причин, по которой мы так долго откладывали добавление необязательных аргументов в C #, было количество сложных неоднозначных ситуаций, которые он вводит в алгоритм разрешения перегрузки; очевидно, мы не поняли это правильно.
Если вы хотите указать проблему с подключением, чтобы отслеживать ее, не стесняйтесь. Если вы просто хотите, чтобы это было доведено до нашего сведения, считайте, что это сделано. Я проведу тестирование в следующем году.
Спасибо, что обратили на это мое внимание. Приносим извинения за ошибку.
'Overloaded.ComplexOverloadResolution(string)'
относится к<string>(string)
методу; Я думаю, это относится к(string, object)
методу без объекта.