2015-04-26 7 views
16

Stavo sperimentando con i generici nameof. Non ho ottenuto il risultato che mi aspettavo. Non sono sicuro se questo fa parte delle specifiche o no.nome di Generics

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

class FooBar<T> { } 

L'output che ottengo è

Hello FooBar!

mi si aspetterebbe alcuni dettagli circa i parametri di tipo.

ho provato con un metodo e che non riesce con un errore di compilazione:

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)

E 'questo perché nameof è un costrutto in fase di compilazione e di farmaci generici sono tipi inizializzato in fase di esecuzione? O c'è qualche altra limitazione?

risposta

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.

Il parametro <T> viene rimosso a causa di trasformazioni identificatore standard (sezione §2.4.2 nelle specifiche C#) che non permettono <> identificatori validi. Prima viene rimosso qualsiasi lead @, quindi le sequenze di escape Unicode vengono trasformate e quindi vengono rimossi tutti i caratteri di formattazione. Questo ovviamente accade ancora in fase di compilazione. È anche possibile vedere questo quando si tenta di stampare il nome di un tipo generico:

typeof(List<string>).Name; 

si tradurrà in:

List`1 

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

è specificato Il secondo errore come non validi in base alla progettazione per evitare complicazioni risoluzione di sovraccarico all'interno 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.

possiamo vedere che chiaramente in t he roslyn codebase:

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)); 
}