带有泛型的名称 [英] nameof with Generics

查看:17
本文介绍了带有泛型的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用泛型试验 nameof.我没有得到我期望的结果.我不确定这是否是规范的一部分.

类 MainClass{公共静态无效主要(字符串[] args){Console.WriteLine ($"Hello { nameof(FooBar)! }");}}类FooBar<T>{ }

我得到的输出是

<块引用>

你好 FooBar!

我希望了解有关类型参数的一些详细信息.

我尝试了一种方法,但由于编译器错误而失败:

类 MainClass{公共静态无效主要(字符串[] args){Console.WriteLine($"Hello { nameof(Do<string>) }");}公共静态 T Do<T>() {}}

<块引用>

错误 CS8084:nameof 运算符的参数不能是具有类型参数的方法组 (CS8084) (foo)

这是因为 nameof 是编译时构造而泛型是在运行时初始化的类型吗?还是有其他限制?

解决方案

我希望了解有关类型参数的一些详细信息

来自设计文档:

<块引用>

nameof 的结果. nameof 的结果取决于它的符号参数绑定到:

一个或多个成员:如果所有成员具有相同的元数据名称,则nameof 的结果就是那个名字;否则是一个错误这参数指的是具有不同名称的多个元素".成员的元数据名称II<isA1...AK>` 只是标准后的I"已应用标识符转换.

<T> 参数被删除,因为标准标识符转换(C# 规范中的第 §2.4.2 节)不允许 <>作为有效的标识符.首先删除所有前导 @,然后转换 Unicode 转义序列,然后删除所有格式化字符.这当然仍然发生在编译时.当您尝试打印出泛型类型的名称时,您也可以看到这一点:

typeof(List).Name;

将导致:

列表`1

<块引用>

这是因为 nameof 是一个编译时构造,而泛型是在运行时初始化的类型?还是有其他限制?

第二个错误被设计为无效,以避免 nameof 内的重载解析复杂化:

<块引用>

允许泛型类型参数? 命名类型时大概是是"因为这就是表达式绑定已经起作用的方式.大概是不".由于使用/推断类型参数而命名方法组时在重载解决期间,必须以 nameof 处理.

我们可以在 roslyn 代码库中清楚地看到这一点:

private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax 节点,诊断包诊断){CheckFeatureAvailability(node.GetLocation(), MessageID.IDS_FeatureNameof, 诊断);var 参数 = node.ArgumentList.Arguments[0].Expression;字符串名称 = "";//我们通过创建 NameofBinder binder 放宽了对顶级成员访问表达式的 instance-vs-static 要求.var nameofBinder = new NameofBinder(argument, this);var boundArgument = nameofBinder.BindExpression(参数,诊断);if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.Kind == BoundKind.MethodGroup){var methodGroup = (BoundMethodGroup)boundArgument;if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty){//不允许有类型参数的方法组diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location);}别的{nameofBinder.EnsureNameofExpressionSymbols(方法组,诊断);}}return new BoundNameOfOperator(node, boundArgument, ConstantValue.Create(name), Compilation.GetSpecialType(SpecialType.System_String));}

有关完整规范,请参阅:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions

I was experimenting with nameof with generics. I didn't get the result I was expecting. I'm not sure if this is part of the spec or not.

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

class FooBar<T> { }

The output I get is

Hello FooBar!

I would expect some details about the type parameters.

I tried it with a method and that fails with a compiler error:

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)

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

解决方案

I would expect some details about the type parameters

From the design docs:

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 IorI< isA1...AK>` is simply "I" after standard identifier transformations have been applied.

The <T> parameter is removed due to standard identifier transformations (section §2.4.2 in the C# specification) which doesn't permit <> as valid identifiers. First any leading @ is removed, then Unicode escape sequences are transformed, and then any formatting characters are removed. This of course still happens at compile-time. You can also see this when you try to print out the name of a generic type:

typeof(List<string>).Name;

Will result 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?

The second error is specified as invalid by design to avoid overload resolution complications inside 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.

We can see that clearly in the 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));
}

For the full specification, see: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions

这篇关于带有泛型的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆