Je ne travaille pas sur le Roslyn équipe, mais je suis assez confiant que c'est un bug. J'ai pris un coup d'oeil au code source et je peux expliquer ce qui se passe.
Tout d'abord, je suis en désaccord avec SLaks répondre que ce n'est pas pris en charge car les méthodes d'extension ne sont pas de déréférencement de leur this
paramètre. C'est une réclamation non fondée, considérant qu'il n'y a aucune mention de cela dans toute la conception de discussions. De Plus, la sémantique de l'opérateur de tourner en somethat qui ressemble plus ou moins à l'opérateur ternaire ((obj == null) ? null : obj.Member
), donc il n'y a pas vraiment une bonne raison pourquoi elle ne pouvait pas être pris en charge dans un sens technique. Je veux dire, lorsqu'il s'agit de code généré, il n'y a vraiment pas de différence dans l'implicite this
sur une méthode d'instance et de l'explicite this
sur la statique de la méthode d'extension.
Le message d'erreur est une bonne idée de ce que c'est un bug, parce que c'est de se plaindre de ce que la méthode n'existe pas, quand il fait réellement. Vous pouvez avoir testé en enlevant l'opérateur conditionnel à partir de l'appel, à l'aide de l'opérateur d'accès au membre au lieu de cela, et d'avoir le code de compiler avec succès. Si il s'agissait d'une utilisation illégale de l'opérateur, vous recevez un message de ce type: error CS0023: Operator '.' cannot be applied to operand of type '<type>'
.
Le bug, c'est que lorsque l' Binder
tente de lier la syntaxe de la compilation des symboles, il utilise une méthode de private static NameSyntax GetNameSyntax(CSharpSyntaxNode, out string)
[lien] qui est le défaut de retourner le nom de la méthode qui est nécessaire quand il essaie de lier l'invocation de l'expression (notre appel de méthode).
Une solution possible consiste à ajouter un extra - case
déclaration à l'interrupteur en GetNameSyntax
[lien] comme suit (Fichier: Compilateurs/CSharp/Source/Liant/Binder_Expressions.cs:2748):
// ...
case SyntaxKind.MemberBindingExpression:
return ((MemberBindingExpressionSyntax)syntax).Name;
// ...
C'était sans doute négligé parce que la syntaxe pour appeler les méthodes d'extension en tant que membres, c'est à l'aide de l'opérateur d'accès au membre du vent à l'aide d'un ensemble différent de syntaxe que lorsqu'il est utilisé avec l'opérateur d'accès au membre contre la condition de l'accès de l'opérateur, en particulier, l' ?.
opérateur utilise un MemberBindingExpressionSyntax
qui n'était pas pris en compte pour qu' GetNameSyntax
méthode.
Fait intéressant, le nom de la méthode n'est pas renseigné pour la première var cr = c?.Get();
qui compile. Il fonctionne, cependant, parce que la méthode local les membres du groupe sont d'abord trouvé pour le type et sont passés à l'appel de l' BindInvocationExpression
[lien]. Lorsque la méthode est résolu (note de l'appel à ResolveDefaultMethodGroup
[lien] avant d'essayer de l' BindExtensionMethod
[lien]), il vérifie d'abord les méthodes et la trouve. Dans le cas de la méthode d'extension, il essaie de trouver une méthode d'extension qui correspond le nom de la méthode qui a été adoptée dans la méthode, qui dans ce cas est une chaîne vide à la place de Get
, et les causes de l'erreur d'erreur sera affiché.
Avec ma version locale de Roslyn avec mon bug fix, je reçois un assembly compilé dont le code ressemble (régénérée à l'aide de 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();
}
}