2015-04-26 2 views
16

Я экспериментировал с nameof с дженериками. Я не получил результат, которого ожидал. Я не уверен, что это часть спецификации или нет.nameof с Generics

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

class FooBar<T> { } 

Выход я получаю

Hello FooBar!

я ожидал бы некоторые подробности о параметрах типа.

Я попробовал его с методом и завершается с ошибкой компилятора:

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)

Является ли это потому, что nameof это время компиляции конструкция и дженерики типы инициализируются во время выполнения? Или есть другие ограничения?

ответ

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.

Параметр <T> удаляется за счет стандартных преобразований идентификаторов (раздел §2.4.2 в C# спецификации), которые не позволяют <>, как действительные идентификаторы. Сначала удаляется любое из ведущих @, затем удаляются последовательности Unicode, а затем удаляются любые символы форматирования. Это, конечно же, происходит во время компиляции. Вы также можете увидеть это при попытке распечатать имя универсального типа:

typeof(List<string>).Name; 

приведет к:

List`1 

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

Уточняется вторая ошибка недействительной конструкции, чтобы избежать осложнения разрешение перегрузки внутри 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.

Мы можем видеть, что явно в т он 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)); 
} 
Смежные вопросы