Подтвердить что ты не робот

Разница между nameof и typeof

Исправьте меня, если я ошибаюсь, но делаю что-то вроде

var typeOfName = typeof(Foo).Name;

и

var nameOfName = nameof(Foo);

должен дать вам точно такой же результат. Одна из понятных причин в соответствии с этим источником: https://msdn.microsoft.com/en-us/library/dn986596.aspx заключается в том, что

"Использование nameof помогает сохранить код при переименовании определений"

Если вы хотите получить экземпляр класса как строку, то не можно сделать что-то вроде этого:

var fooInstance = new Foo();
var nameOfName = nameof(fooInstance);

однако вы можете сделать что-то вроде:

static string GetName<T>(T item) where T : class 
{
  return typeof(T).GetProperties()[0].Name;
}
var typeOfName2 = GetName(new { fooInstance });

В обоих случаях (typeof и nameof) рефакторинг возможен, поэтому я не вижу другой причины для повторного использования другого ключевого слова более высокого уровня, такого как nameof, для выполнения чего-то, что уже существует. Есть ли различия между ними, которые я не вижу?

Наконец, я был бы признателен, если бы кто-то мог указать мне на источник ссылок, чтобы посмотреть на реализацию nameof. Использует ли Reflection?

Обновление 1: Взято из здесь

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)
4b9b3361

Ответ 1

Две причины:

nameof превращается в константу времени компиляции. typeof(...).Name требует немного отражения. Это не слишком дорого, но в некоторых случаях это может повредить.

Во-вторых, он используется для других вещей, кроме имен типов. Например, аргументы:

void SomeMethod(int myArgument)
{
  Debug.WriteLine(nameof(myArgument));
}

Вы также можете получить имя членов класса и даже локальных жителей. Излишне говорить, что это очень полезно для отладки информации. Это также один из способов реализации менее хрупкого отражения, когда, например, синтаксический анализ деревьев выражений (к сожалению, в проекте, где я буду использовать это, мы все еще придерживаемся .NET 4.0 с С# 5 - это спасло бы меня от нескольких хаков здесь и там).

И чтобы устранить некоторую путаницу, nameof не является функцией, а также не является typeof. Это оператор времени компиляции, и он всегда оценивается во время компиляции (хотя, очевидно, generics быстрее перемещают "время компиляции" ).

Ответ 2

Использование Reflection для генерации строк возможно, но не очень изящно и не всегда возможно. Например, вы не можете использовать Reflection в изолированном коде. И вы не можете использовать его для локальных переменных. И это дорого.

Оператор nameof работает во время компиляции. Компилятор уже знает имя, когда он анализирует код. Таким образом, можно тривиально генерировать строковый литерал. Очень быстро, не может быть быстрее, и никаких ограничений времени выполнения.

Ответ 3

Между ними существует несколько различий, но в основном это практические причины. Пример 1:

Более элегантно писать что-то вроде

switch (e.ArgumentPropertyName)
{
    case nameof(aProperty):
    break;

    case "anotherProperty":
    break;
}

Попробуйте реорганизовать тип anotherProperty и удар! nameof будет отражать изменения, "anotherProperty" пройдет молча, и ваш код никогда не будет выполнен в этом случае.

Пример 2:

enum MetalEnum { Gold = 1,  Silver = 2, ... }

Какой из них лучше?

Console.WriteLine(MetalEnum.Gold.ToString()); // finds the name at runtime (slower)

или

Console.WriteLine(nameof(MetalEnum.Gold)); // compile time (faster)

Пример 3:

Наконец, вы помните, как уродливо писать что-то вроде

PropertyChanged(this, new PropertyChangedEventArgs("Foo"));

Теперь вы можете писать так красиво, как показано ниже:

PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));

Ответ 4

Здесь тестовый тест с использованием BenchmarkDotNet

// * Summary *

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Windows
Processor=?, ProcessorCount=8
Frequency=2740584 ticks, Resolution=364.8857 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003133

Type=GetNameBenchmark  Mode=Throughput  LaunchCount=2
WarmupCount=10  TargetCount=200

     Method |     Median |    StdDev |
----------- |----------- |---------- |
     TypeOf | 16.0348 ns | 0.7896 ns |
     NameOf |  0.0005 ns | 0.0147 ns |

Ответ 5

Тип возвращает объекты типа. Он часто используется как параметр или как переменная или поле. Оператор typeof является частью выражения, которое получает указатель типа.

class Program
{
    static Type _type = typeof(char); // Store Type as field.

    static void Main()
    {
    Console.WriteLine(_type); // Value type pointer
    Console.WriteLine(typeof(int)); // Value type
    Console.WriteLine(typeof(byte)); // Value type
    Console.WriteLine(typeof(Stream)); // Class type
    Console.WriteLine(typeof(TextWriter)); // Class type
    Console.WriteLine(typeof(Array)); // Class type
    Console.WriteLine(typeof(int[])); // Array reference type
    }
}

Выход

System.Char
System.Int32
System.Byte
System.IO.Stream
System.IO.TextWriter
System.Array
System.Int32[]

Nameof, тем временем, возвращает строку с именем переменной. Он работает во время компиляции. Это специальная функция компилятора, которая упрощает некоторые программы.

int size=100;
Console.WriteLine(nameof(size));

вывод: размер

Ответ 6

В соответствии с документация:

Используется для получения простого (неквалифицированного) имени строки для переменной, типа или члена.

...

Аргументом для nameof должно быть простое имя, квалифицированное имя, доступ к члену, базовый доступ с указанным членом или этот доступ с указанным членом. Выражение аргумента идентифицирует определение кода, но оно никогда не оценивается.

Поскольку аргумент должен быть синтаксическим выражением, существует множество вещей, которые не могут быть перечислены. Следует упомянуть следующие ошибки: предопределенные типы (например, int или void), типы с нулевым значением (Point?), типы массивов (Customer[,]), типы указателей (Buffer*), квалифицированный псевдоним (A::B) и несвязанные общие типы (Dictionary<,>), символы предварительной обработки (DEBUG) и метки (loop:).

Простое имя, получаемое nameof, - это имя источника, а не имя метаданных.

Итак, этот код:

using Integer = System.Int32;
var s = "a string";
Console.WriteLine(nameof(s));
Console.WriteLine(nameof(Integer));
Console.WriteLine(nameof(System.Int32));
void M<T>() { Console.WriteLine(nameof(T)); }
M<int>();
M<string>();

напечатает:

s
Integer
Int32
T
T

Ответ 7

Typeof возвращает объекты типа. Он часто используется как параметр или как переменная или поле. Оператор typeof является частью выражения, которое получает указатель типа.

Nameof, тем временем, возвращает строку с именем переменной. Он работает во время компиляции. Это специальная функция компилятора, которая упрощает некоторые программы.