Какова цель имени?
Версия 6.0 получила новую функцию nameof
, но я не могу понять ее цели, поскольку она просто принимает имя переменной и изменяет ее на строку в компиляции.
Я думал, что это может иметь определенную цель при использовании <T>
, но когда я пытаюсь nameof(T)
, он просто печатает мне T
вместо используемого типа.
Любая идея с этой целью?
Ответы
Ответ 1
Как насчет случаев, когда вы хотите повторно использовать имя свойства, например, при бросании исключения на основе имени свойства или обработки события PropertyChanged
. Существует множество случаев, когда вы хотели бы иметь имя свойства.
Возьмем этот пример:
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break };
// opposed to
case "SomeOtherProperty":
{ break;}
}
В первом случае переименование SomeProperty
также изменит имя свойства, иначе оно сломает компиляцию. В последнем случае нет.
Это очень полезный способ сохранить компиляцию кода и ошибку (сортировку).
(A очень хорошая статья от Эрика Липперта, почему infoof
не сделал этого, а nameof
сделал)
Ответ 2
Это действительно полезно для ArgumentException
и его производных:
public string DoSomething(string input)
{
if(input == null)
{
throw new ArgumentNullException(nameof(input));
}
...
Теперь, если кто-то реорганизует имя параметра input
, исключение также будет обновляться.
Это также полезно в некоторых местах, где раньше нужно было использовать отражение, чтобы получить имена свойств или параметров.
В вашем примере nameof(T)
получает имя параметра типа - это тоже может быть полезно:
throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");
Другое использование nameof
для перечислений - обычно, если вы хотите, чтобы имя строки перечисления использовалось .ToString()
:
enum MyEnum { ... FooBar = 7 ... }
Console.WriteLine(MyEnum.FooBar.ToString());
> "FooBar"
Это относительно медленно, так как .Net содержит значение перечисления (т.е. 7
) и находит имя во время выполнения.
Вместо этого используйте nameof
:
Console.WriteLine(nameof(MyEnum.FooBar))
> "FooBar"
Теперь .Net заменяет имя перечисления на строку во время компиляции.
Еще одно использование для таких вещей, как INotifyPropertyChanged
и протоколирование - в обоих случаях вы хотите, чтобы имя члена, которое вы вызываете, передавалось другому методу:
// Property with notify of change
public int Foo
{
get { return this.foo; }
set
{
this.foo = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
}
}
Или...
// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
Log(nameof(DoSomething), "Message....");
}
Ответ 3
Ваш вопрос уже выражает цель. Вы должны увидеть, что это может быть полезно для регистрации или исключения исключений.
например.
public void DoStuff(object input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
}
это хорошо, , если я изменю имя переменной, которую код сломает или вернет исключение с неправильным сообщением.
Конечно, использование не ограничивается этой простой ситуацией. Вы можете использовать nameof
всякий раз, когда было бы полезно закодировать имя переменной или свойства.
Использование многообразно, если вы рассматриваете различные ситуации привязки и отражения. Это отличный способ принести ошибки времени выполнения для компиляции времени.
Ответ 4
Самый распространенный случай использования, о котором я могу думать, - это работать с интерфейсом INotifyPropertyChanged
. (В основном все, что связано с WPF и привязками, использует этот интерфейс)
Взгляните на этот пример:
public class Model : INotifyPropertyChanged
{
// From the INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
private string foo;
public String Foo
{
get { return this.foo; }
set
{
this.foo = value;
// Old code:
PropertyChanged(this, new PropertyChangedEventArgs("Foo"));
// New Code:
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));
}
}
}
Как вы можете видеть по-старому, нам нужно передать строку, чтобы указать, какое свойство изменилось. С помощью nameof
мы можем напрямую использовать имя свойства. Это может показаться неважным. Но изображение того, что происходит, когда кто-то меняет имя свойства Foo
. При использовании строки привязка перестанет работать, но компилятор не предупредит вас. При использовании nameof вы получаете ошибку компилятора, что нет свойства/аргумента с именем Foo
.
Обратите внимание, что некоторые фреймворки используют магию отражения, чтобы получить имя свойства, но теперь у нас есть имя этого уже не обязательно.
Ответ 5
Наиболее распространенное использование будет при проверке ввода, например
//Currently
void Foo(string par) {
if (par == null) throw new ArgumentNullException("par");
}
//C# 6 nameof
void Foo(string par) {
if (par == null) throw new ArgumentNullException(nameof(par));
}
В первом случае, если вы реорганизуете метод, изменяющий имя параметра par, вы, вероятно, забудете изменить это в ArgumentNullException. С именем вам не нужно беспокоиться об этом.
Смотрите также: nameof (ссылка на С# и Visual Basic)
Ответ 6
Здесь есть много хороших ответов. Я хотел бы добавить еще одну утилиту, где эта функция nameof
С# 6.0 становится удобной. Рассмотрим библиотеку, например Dapper, что облегчает извлечение БД. Хотя это отличная библиотека, вам нужно жестко указать имена свойств в запросе, что не позволяет компилятору находить неправильные имена свойств. Благодаря функции интерполяции строк и функций nameof это становится намного проще и типично.
В примере, приведенном в ссылке
без имени
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
с именемof
var dog = connection.Query<Dog>($"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id", new { Age = (int?)null, Id = guid });
Ответ 7
Как уже указывалось другими, оператор nameof
вставляет имя, которое элемент был указан в исходном коде.
Я хотел бы добавить, что это действительно хорошая идея с точки зрения рефакторинга, поскольку он делает эту рефакторингу этой строки безопасной. Раньше я использовал статический метод, который использовал отражение для той же цели, которая, однако, имеет влияние производительности во время выполнения. Оператор nameof
не имеет влияния на производительность во время выполнения, он выполняет свою работу по времени компиляции. Если вы посмотрите на код MSIL
, вы найдете строку, встроенную. См. Следующий метод и его дизассемблированный код.
static void Main(string[] args)
{
Console.WriteLine(nameof(args));
Console.WriteLine("regular text");
}
// striped nops from the listing
IL_0001 ldstr args
IL_0006 call System.Void System.Console::WriteLine(System.String)
IL_000C ldstr regular text
IL_0011 call System.Void System.Console::WriteLine(System.String)
IL_0017 ret
Однако это может быть недостатком, если вы планируете запутывать свое программное обеспечение. После обфускации встроенная строка может больше не соответствовать имени элемента. Механизмы, которые полагаются на этот текст, сломаются. Примерами для этого, включая, но не ограничиваясь, являются: Reflection, NotifyPropertyChanged...
Определение имени во время выполнения требует некоторой производительности, но безопасно для обфускации. Если обфускация не требуется и не планировалась, я бы рекомендовал использовать оператор nameof
.
Ответ 8
Учтите, что вы используете переменную в своем коде и должны получить имя переменной и, скажем, напечатать ее, вам следует использовать
int myVar = 10;
print("myVar" + " value is " + myVar.toString());
И если тогда кто-то реорганизует код и использует другое имя для "myVar", ему/ей придется следить за строковым значением в вашем коде и делать его соответствующим образом.
Вместо этого, если у вас
print(nameof(myVar) + " value is " + myVar.toString());
Это поможет реорганизовать автоматически!
Ответ 9
В статье MSDN перечислены маршруты MVC (пример, который действительно нажал на концепцию для меня) среди нескольких других. Абзац описания (форматированный) гласит:
- При сообщении ошибок в коде
- подключение ссылок на модель-просмотр-контроллер (MVC),
- события с изменением обжига, и т.д.,
вы часто хотите захватить имя строки метода. Использование nameof помогает сохранить код действителен при переименовании определений.
Прежде чем вам пришлось использовать строковые литералыдля обозначения определений , который является хрупким при переименовании элементов кода , потому что инструменты не знают, чтобы проверить эти строковые литералы.
Принятые/высоко оцененные ответы уже дают несколько отличных конкретных примеров.
Ответ 10
В проекте ASP.NET Core MVC используется nameof
в AccountController.cs
и ManageController.cs
с помощью метода RedirectToAction
для ссылки на действие в контроллере.
Пример:
return RedirectToAction(nameof(HomeController.Index), "Home");
Это означает:
return RedirectToAction("Index", "Home");
и берет пользователя в действие "Индекс" в "Домашнем" контроллере, т.е. /Home/Index
.
Ответ 11
Цель оператора nameof
- предоставить исходное имя артефактов.
Обычно имя источника совпадает с именем метаданных:
public void M(string p)
{
if (p == null)
{
throw new ArgumentNullException(nameof(p));
}
...
}
public int P
{
get
{
return p;
}
set
{
p = value;
NotifyPropertyChanged(nameof(P));
}
}
Но это не всегда так:
using i = System.Int32;
...
Console.WriteLine(nameof(i)); // prints "i"
Или:
public static string Extension<T>(this T t)
{
return nameof(T); returns "T"
}
Одно использование, которое я ему давал, это для именования ресурсов:
[Display(
ResourceType = typeof(Resources),
Name = nameof(Resources.Title_Name),
ShortName = nameof(Resources.Title_ShortName),
Description = nameof(Resources.Title_Description),
Prompt = nameof(Resources.Title_Prompt))]
Дело в том, что в этом случае мне даже не нужны сгенерированные свойства для доступа к ресурсам, но теперь у меня есть проверка времени компиляции, что ресурсы существуют.
Ответ 12
Одним из использования ключевого слова nameof
является установка Binding
в wpf программно.
чтобы установить Binding
, вы должны установить Path
со строкой и с ключевым словом nameof
, возможно использовать опцию Refactor.
Например, если у вас есть свойство IsEnable
dependency в UserControl
и вы хотите привязать его к IsEnable
некоторого CheckBox
в UserControl
, вы можете использовать эти два кода:
CheckBox chk = new CheckBox();
Binding bnd = new Binding ("IsEnable") { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
и
CheckBox chk = new CheckBox();
Binding bnd = new Binding (nameof (IsEnable)) { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
Очевидно, что первый код не может рефакторировать, но секвенция...
Ответ 13
Раньше мы использовали что-то вроде этого:
// Some form.
SetFieldReadOnly( () => Entity.UserName );
...
// Base form.
private void SetFieldReadOnly(Expression<Func<object>> property)
{
var propName = GetPropNameFromExpr(property);
SetFieldsReadOnly(propName);
}
private void SetFieldReadOnly(string propertyName)
{
...
}
Причина - сберечь время. Никто не может молча переименовать свойство и нарушить логику кода. Теперь мы можем использовать nameof().