2015-04-26 11 views
16

Eksperymentowałem z nameof z rodzajami. Nie osiągnąłem oczekiwanego rezultatu. Nie jestem pewien, czy jest to część specyfikacji, czy nie.nameof z generics

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

class FooBar<T> { } 

Wyjście mogę to

Hello FooBar!

spodziewałbym kilka szczegółów na temat parametrów typu.

próbowałem go z metodą i że nie powiedzie się z błąd kompilatora:

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)

Czy to dlatego nameof jest konstruktem kompilacji i generyczne są rodzaje zainicjowany w czasie wykonywania? Czy jest jakieś inne ograniczenie?

Odpowiedz

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.

Parametr <T> usuwa się ze względu na standardowe transformowanie identyfikatora (rozdział §2.4.2 w opisie C#), który nie dopuszcza <> za ważne identyfikatorów. Najpierw usuwane są wszystkie wiodące znaki @, a następnie sekwencje specjalne Unicode są przekształcane, a następnie usuwane są wszelkie znaki formatujące. To oczywiście nadal dzieje się podczas kompilacji. Można również zobaczyć podczas próby wydrukowania nazwy typu rodzajowego:

typeof(List<string>).Name; 

spowoduje:

List`1 

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

Drugi błąd jest określony jako nieważne zaprojektowanych tak, by uniknąć rozdzielczość przeciążenie komplikacje wewnątrz 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.

Widzimy wyraźnie, że w t on kod: Roslyn code:

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