首页 > 解决方案 > 为什么 nameof 不能与根级别的别名限定类型一起使用?

问题描述

想象一下根命名空间级别的类型(可能在默认global空间中,或者可能是一个extern alias)。

使用别名前缀时,似乎无法通过 引用此类型。nameof()它适用于typeof, 和 viausing别名(尽管nameofusing别名上产生别名,而不是类型名)。带有 CS8083 的编译器对象,“别名限定名称不是表达式。”

但是:这是有原因的吗?这是为了防止一些模糊的问题场景吗?或满足一些规格要求?或者它可能是一个编译器错误?我也很满意地注意到我们通常不应该在命名空间根中声明类型——CA1050这是非常正确的;但这不是重点:)

完整示例如下;请注意,在此示例中使用两个项目进行using别名检查,但为简单起见,所有涉及的内容C都可以忽略以进行简单调查。

extern alias foo;
using System;
using X = global::A;
using Y = global::FunWithNamespaces.B;
using Z = foo::C;

public class A { }

namespace FunWithNamespaces
{
    public class B { }
    public class Program
    {
        static void Main()
        {
            // oddness is on the lines marked ## CS8083

            // relative-qualified using typeof
            Console.WriteLine(typeof(X).Name); // A, expected
            Console.WriteLine(typeof(Y).Name); // B, expected
            Console.WriteLine(typeof(Z).Name); // C, expected
            Console.WriteLine(typeof(A).Name); // A
            Console.WriteLine(typeof(B).Name); // B
            // note: can't talk about C without using an alias qualifier or a using-alias
            Console.WriteLine(typeof(Console).Name); // Console

            // relative-qualified things using nameof
            Console.WriteLine(nameof(X)); // X; I'm on the fence about X vs A, but... whatever
            Console.WriteLine(nameof(Y)); // Y; I'm on the fence about Y vs B, but... whatever
            Console.WriteLine(nameof(Z)); // Z; I'm on the fence about Z vs C, but... whatever
            Console.WriteLine(nameof(A)); // A
            Console.WriteLine(nameof(B)); // B
            // note: can't talk about C without using an alias qualifier or a using-alias
            Console.WriteLine(nameof(Console)); // Console

            // alias-qualified things using typeof
            Console.WriteLine(typeof(global::A).Name); // A
            Console.WriteLine(typeof(global::FunWithNamespaces.B).Name); // B
            Console.WriteLine(typeof(foo::C).Name); // C
            Console.WriteLine(typeof(global::System.Console).Name); // Console

            // alias-qualified things using nameof
            // ??? Console.WriteLine(nameof(global::A)); // ## CS8083 An alias-qualified name is not an expression
            Console.WriteLine(nameof(global::FunWithNamespaces.B)); // B
            // ??? Console.WriteLine(nameof(foo::C)); // ## CS8083 An alias-qualified name is not an expression
            Console.WriteLine(nameof(global::System.Console)); // Console
        }
        
    }
}

whereC在单独的程序集中定义并使用指定为 的别名引用foo,并且很简单:

public class C { }

编辑:就规范而言,这归结为https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#nameof-expressions,其中 anameof_expression必须是simple_name(它不是)或named_entity_target '.' identifier type_argument_list?- 所以:对于所有不是简单名称的情况,必须.something- 但我想这里的根本问题是为什么必须有 a .something, 而其他一些允许的结构global::Foo?例如:

nameof_expression
    : 'nameof' '(' named_entity ')'
    ;

named_entity
    : simple_name
    | named_entity_target '.' identifier type_argument_list?
    | qualified_alias_member type_argument_list?
    ;

named_entity_target
    : 'this'
    | 'base'
    | named_entity 
    | predefined_type 
    | qualified_alias_member
    ;

标签: c#nameof

解决方案


表达式的解析是在编译期间完成的,因此会出现 CSxxx 编译错误。所以操作符nameof()在运行时没有任何作用。

另外,它可能会使用.Net Reflection来获取您作为参数提供的值的名称。因此,要通过反射解析类型,编译器需要成员的“完整路径”(即从名称空间到它)。


推荐阅读