2015-04-26 3 views
16

Ich experimentierte mit nameof mit Generika. Ich habe das Ergebnis, das ich erwartet hatte, nicht bekommen. Ich bin mir nicht sicher, ob dies Teil der Spezifikation ist oder nicht.nameof with Generics

class MainClass 
{ 
    public static void Main (string[] args) 
    { 
     Console.WriteLine ($"Hello { nameof(FooBar<string>)! }"); 
    } 
} 

class FooBar<T> { } 

Der Ausgang ich erhalte, ist

Hello FooBar!

ich einige Details über die Art Parameter erwarten.

Ich versuchte es mit einem Verfahren und das nicht klappt mit einem Compiler-Fehler:

class MainClass 
{ 
    public static void Main (string[] args) 
    { 
     Console.WriteLine ($"Hello { nameof(Do<string>) }"); 
    } 

    public static T Do<T>() {} 
} 

Error CS8084: An argument to nameof operator cannot be method group with type arguments (CS8084) (foo)

Ist dies, weil nameof ist ein Kompilierung-Konstrukt und Generika-Typen zur Laufzeit initialisiert? Oder gibt es eine andere Einschränkung?

Antwort

16

I would expect some details about the type parameters

The "spec" says:

Result of nameof. The result of nameof depends on the symbols that its argument bound to:

One or more members: if all members have the same metadata name then the result of nameof is that name; otherwise it is an error "This argument refers to multiple elements with different names". The metadata name of a member I or I< isA1...AK>` is simply "I" after standard identifier transformations have been applied.

Der <T> Parameter aufgrund Standardbezeichner Transformationen (§ 2.4.2 Abschnitt in der C# Spezifikation) entfernt wird, die nicht als gültige <> Identifikatoren zulässt. Zuerst wird ein führendes @ entfernt, dann werden Unicode-Escape-Sequenzen transformiert und dann werden alle Formatierungszeichen entfernt. Dies geschieht natürlich noch zur Kompilierzeit. Sie können dies auch sehen, wenn Sie versuchen, den Namen eines generischen Typs auszudrucken:

typeof(List<string>).Name; 

in Folge hat:

List`1 

Is this because nameof is a compile-time construct and generics are types initialized at runtime? Or is there some other limitation?

Der zweite Fehler angegeben wird, wie durch Design ungültig zu vermeiden Überladungsauflösung Komplikationen innerhalb nameof:

Allow generic type arguments? Presumably 'yes' when naming a type since that's how expression binding already works. And presumably 'no.' when naming a method-group since type arguments are used/inferred during overload resolution, and it would be confusing also to have to deal with that in nameof.

können wir das deutlich in t sehen er Roslyn Codebasis:

private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax node, 
                DiagnosticBag diagnostics) 
{ 
    CheckFeatureAvailability(node.GetLocation(), MessageID.IDS_FeatureNameof, diagnostics); 

    var argument = node.ArgumentList.Arguments[0].Expression; 
    string name = ""; 

    // We relax the instance-vs-static requirement for top-level member access expressions by creating a NameofBinder binder. 
    var nameofBinder = new NameofBinder(argument, this); 
    var boundArgument = nameofBinder.BindExpression(argument, diagnostics); 

    if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.Kind == BoundKind.MethodGroup) 
    { 
     var methodGroup = (BoundMethodGroup)boundArgument; 
     if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty) 
     { 
      // method group with type parameters not allowed 
      diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location); 
     } 
     else 
     { 
      nameofBinder.EnsureNameofExpressionSymbols(methodGroup, diagnostics); 
     } 
    } 

    return new BoundNameOfOperator(node, boundArgument, ConstantValue.Create(name), Compilation.GetSpecialType(SpecialType.System_String)); 
}