2015-11-11 1 views
13

Поправьте меня, если я не прав, но делать что-то вродеразница между 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. Использует ли он отражение?

Update 1: Взятые из here

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) 
+1

'nameof (fooInstance)' возвращает ' "fooInstance" '. С 'nameof' вы получаете имя переменной, а не имя типа. –

+0

получает строковую версию переменной. nameof (aaa) вернет «aaa» –

+2

'static string GetName (T item)' делает что-то совершенно иное, чем 'typeof' или' nameof'. Он возвращает имя случайного свойства, которое имеет тип. Это может также вызвать исключение, если оно используется по-другому, чем предполагалось. –

ответ

19

Два причины:

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

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

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

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

И для устранения некоторых замешательств, nameof is не a функция, и ни одна из них не является typeof.Это оператор времени компиляции, и он всегда оценивается во время компиляции (хотя, очевидно, generics больше «компилируют время» вовремя).

2

Тип Тип объекта. Он часто используется как параметр или как переменная или поле. Оператор 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)); 

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

7

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

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

0

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

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

4

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

Это более элегантный, чтобы написать что-то вроде

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

    case "anotherProperty": 
    break; 
} 

Try реорганизовать 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))); 
1

В соответствии с the documentation:

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

...

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

Поскольку аргумент должен быть синтаксическим выражением, есть много недопустимых вещей, которые не являются полезными для перечисления. Ниже приведено стоит отметить, что ошибки производят: предопределенные типов (например, INT или недействительные), обнуляемые типов (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 
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 | 
+0

Спасибо за указание BenchmarkDotNet ... никогда не слышал об этом раньше – KornMuffin

Смежные вопросы