Ответ 1
Я не работаю над командой Roslyn, но я уверен, что это ошибка. Я взглянул на исходный код, и я могу объяснить, что происходит.
Во-первых, я не согласен с SLaks ответить, что это не поддерживается, потому что методы расширения не разыгрывают их параметр this
. Это необоснованное утверждение, учитывая, что в нем не упоминается ни один из дизайн discussions. Кроме того, семантика оператора превращается в нечто примерно похожее на тернарный оператор ((obj == null) ? null : obj.Member
), поэтому на самом деле нет веской причины, почему его нельзя поддерживать в техническом смысле. Я имею в виду, что когда он сводится к сгенерированному коду, действительно нет никакой разницы в неявном this
на методе экземпляра и явном this
на статическом методе расширения.
Сообщение об ошибке - это хорошая подсказка, что это ошибка, потому что она жалуется, что метод не существует, когда он это делает. Возможно, вы протестировали это, удалив условный оператор из вызова, используя вместо этого оператор доступа к члену и успешно скомпилировав код. Если это было незаконным использованием оператора, вы получите сообщение, подобное этому: error CS0023: Operator '.' cannot be applied to operand of type '<type>'
.
Ошибка заключается в том, что когда Binder
пытается привязать синтаксис к скомпилированным символам, он использует метод private static NameSyntax GetNameSyntax(CSharpSyntaxNode, out string)
[link], который не возвращает имя метода, которое необходимо, когда оно пытается связать выражение вызова (наш вызов метода).
Возможное исправление заключается в добавлении дополнительной инструкции case
к коммутатору в GetNameSyntax
[link] следующим образом (Файл: Компиляторы /CSharp/Source/Binder/Binder _Expressions.cs: 2748):
// ...
case SyntaxKind.MemberBindingExpression:
return ((MemberBindingExpressionSyntax)syntax).Name;
// ...
Это, вероятно, было упущено, потому что синтаксис для вызова методов расширения как членов, использующий оператор доступа к члену) завершается с использованием другого набора синтаксиса, чем при использовании с оператором доступа к члену и оператору условного доступа, оператор ?.
использует MemberBindingExpressionSyntax
, который не был учтен для этого метода GetNameSyntax
.
Интересно, что имя метода не заполняется для первого var cr = c?.Get();
, который компилируется. Он работает, однако, потому что локальные члены группы методов сначала найдены для типа и передаются на вызов BindInvocationExpression
[ссылка]. Когда метод устраняется (обратите внимание на вызов ResolveDefaultMethodGroup
[link] перед тем, как попробовать BindExtensionMethod
[ссылка], он сначала проверяет эти методы и находит их. В случае метода расширения он пытается найти метод расширения, который соответствует имени метода, который был передан в метод, который в этом случае был пустой строкой вместо Get
, и вызывает отображение ошибочной ошибки.
С моей локальной версией Roslyn с исправлением ошибки я получаю скомпилированную сборку, код которой выглядит (регенерируется с помощью dotPeek):
internal class Program
{
private static void Main(string[] args)
{
C c1 = (C) null;
object obj1 = c1 != null ? c1.Get() : (object) null;
CC c2 = (CC) null;
object obj2 = c2 != null ? CCExtensions.Get(c2) : (object) null;
Console.ReadLine();
}
}