Определяется ли имяof() во время компиляции?

В С# 6 вы можете использовать оператор nameof(), чтобы получить строку, содержащую имя переменной или типа.

Проверяется ли это во время компиляции или во время выполнения через некоторый API Roslyn?

Вы можете прочитать о nameof() операторе answer, или выделенное сообщение в моем блоге. На сайте 2000things.com вы найдете описание и пример его использования.

Ответы

Ответ 1

Да. nameof() оценивается во время компиляции. Посмотрев последнюю версию спецификации:

Имя выражения является константой. Во всех случаях имяof (...) оценивается во время компиляции для создания строки. Его аргумент не оценивается во время выполнения и считается недостижимым кодом (однако он не выводит предупреждение "недостижимый код" ).

Из nameof operator - v5

Вы можете увидеть это с помощью этого примера TryRoslyn, где это:

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

Будет:

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

Ответ 2

Я хотел обогатить ответ, предоставленный @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 эффективен, как объявление строковой переменной.