nameof()是在编译时评估的吗?

时间:2014-10-26 12:44:35

标签: c# roslyn c#-6.0

在C#6中,您可以使用nameof()运算符来获取包含变量名称或类型的字符串。

这是在编译时评估,还是在运行时通过一些Roslyn API进行评估?

2 个答案:

答案 0 :(得分:113)

是。 nameof()在编译时进行评估。查看最新版本的规范:

  

表达式的名称是常量。在所有情况下,nameof(...)在编译时评估以生成字符串。它的参数在运行时不会被评估,并且被认为是无法访问的代码(但它不会发出"无法访问的代码"警告)。

来自nameof operator - v5

您可以在this TryRoslyn example处看到以下内容:

public class Foo
{
    public void Bar()
    {
        Console.WriteLine(nameof(Foo));
    }
}

编译并反编译成:

public class Foo
{
    public void Bar()
    {
        Console.WriteLine("Foo");
    }
}

它的运行时等价物是:

public class Foo
{
    public void Bar()
    {
        Console.WriteLine(typeof(Foo).Name);
    }
}

正如评论中所提到的,这意味着当您对泛型类型中的类型参数使用nameof时,不要期望获取用作类型参数的实际动态类型的名称只是类型参数的名称。所以这个:

public class Foo
{
    public void Bar<T>()
    {
        Console.WriteLine(nameof(T));
    }
}

Will become这个:

public class Foo
{
    public void Bar<T>()
    {
        Console.WriteLine("T");
    }
}

答案 1 :(得分:58)

我希望通过证明它在编译时进行评估来丰富the answer provided by @I3arnon

假设我想使用nameof运算符在控制台中打印变量的名称:

 var firstname = "Gigi";
 var varname = nameof(firstname);
 Console.WriteLine(varname); // Prints "firstname" to the console

当您查看生成的MSIL时,您将看到它等同于字符串声明,因为使用ldstr运算符将对字符串的对象引用推送到堆栈:

IL_0001: ldstr "Gigi"
IL_0006: stloc.0
IL_0007: ldstr "firstname"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: call void [mscorlib]System.Console::WriteLine(string)

您会注意到声明firstname字符串并使用nameof运算符在MSIL中生成相同的代码,这意味着nameof与声明字符串变量一样高效。