Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Оператор
Подсказка
Эта статья является частью раздела "Основы" для разработчиков , которые уже знают хотя бы один язык программирования и учат C#. Если вы не знакомы с программированием, сначала начните с учебных пособий по началу работы. Полное справочное описание оператора см. в разделе nameof справочника по языку.
Вы пришли из другого языка? Другие языки имеют аналогичные функции. рефлексивный Class.getSimpleName() в Java, Function.name и Object.keys в JavaScript, __name__ и vars() в Python и #function/#keyPath в Swift. В отличие от большинства из них, nameof в C# является исключительно компиляционной конструкцией. Не использует рефлексию, ничего не выделяет во время выполнения и создает константу string, встроенную в сборку.
Оператор nameof возвращает текстовый идентификатор символа, например переменную, параметр, тип, член или пространство имен в виде константы во время string компиляции. Везде, где иначе пришлось бы жёстко задавать идентификатор строкой, используйте nameof: компилятор проверяет, что символ существует, а рефакторинг переименования автоматически обновляет результат.
Что nameof возвращается
nameof принимает значение последнего идентификатора в своём операнде. Это происходит на этапе компиляции и не влечёт накладных расходов во время выполнения.
// nameof produces the textual identifier of a symbol at compile time.
Console.WriteLine(nameof(Customer)); // Customer
Console.WriteLine(nameof(Customer.Name)); // Name
var customer = new Customer("Ada");
Console.WriteLine(nameof(customer)); // customer
Console.WriteLine(nameof(customer.Name)); // Name
Операнды также могут быть квалифицированным выражением, который использует оператор dot для перехода из содержащей области в элемент, например customer.Name, System.Consoleили List<int>.Enumerator. В этом случае фиксируется только последний идентификатор: nameof(customer.Name) возвращается "Name", а не "customer.Name".
Проверка аргументов
Классический вариант использования заключается в указании имени параметра в выбрасываемом исключении. Передайте nameof(parameter) вместо строкового литерала "parameter", чтобы будущее переименование не сделало сообщение недостоверным:
try
{
Greet("");
}
catch (ArgumentException ex)
{
// The exception's ParamName is the literal "name", produced by nameof at compile time.
Console.WriteLine($"{ex.ParamName}: {ex.Message}");
}
static void Greet(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name must be non-empty.", nameof(name));
}
Console.WriteLine($"Hello, {name}!");
}
В частности для проверок на null предпочтительно использовать вспомогательные методы для создания исключений. Эти вспомогательные средства, такие как ThrowIfNull, автоматически захватывают имя аргумента с помощью CallerArgumentExpressionAttribute, поэтому отдельный nameof не требуется:
// ArgumentNullException.ThrowIfNull captures the argument's name automatically
// through [CallerArgumentExpression], so a separate nameof isn't required for
// the null check. Use nameof for cases the helpers don't cover.
Customer? maybeCustomer = null;
try
{
Save(maybeCustomer);
}
catch (ArgumentNullException ex)
{
Console.WriteLine(ex.ParamName); // customer
}
static void Save(Customer? customer)
{
ArgumentNullException.ThrowIfNull(customer);
// ...
}
Используйте nameof в случаях, когда вспомогательные средства не охватывают: ArgumentExceptionArgumentOutOfRangeException(при проверке чего-либо другого, кроме одного аргумента), а также других сообщений защиты.
Уведомления об изменении свойств
Типы, реализующие INotifyPropertyChanged, вызывают событие, полезная нагрузка которого включает имя измененного свойства. Жёсткое задание имени в виде строки создаёт скрытую ошибку, если свойство переименуют, а строку — нет. Используйте nameof вместо этого:
public sealed class Person : INotifyPropertyChanged
{
private string _name = "";
public string Name
{
get => _name;
set
{
if (_name == value) return;
_name = value;
// nameof keeps the property name and the change notification in sync.
// Renaming the property automatically updates this argument.
OnPropertyChanged(nameof(Name));
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Сеттер вызывает OnPropertyChanged(nameof(Name)), поэтому имя свойства и уведомление об изменении остаются синхронизированными. Запустите пример, чтобы увидеть, как срабатывают события:
var person = new Person();
person.PropertyChanged += (_, e) => Console.WriteLine($"changed: {e.PropertyName}");
person.Name = "Ada"; // changed: Name
person.Name = "Grace"; // changed: Name
nameof в аргументах атрибутов
nameof допустим в аргументах атрибутов. Компилятор разрешает идентификаторы в окружающей области, включая параметры метода, целевые объекты атрибута. Это идиоматический способ ссылаться на параметр из атрибута, NotNullIfNotNullAttributeнапример:
// nameof works inside attribute arguments. The compiler resolves the
// identifier even when the attribute targets a method or its parameters.
Console.WriteLine(NormalizeOrNull(" hi ") ?? "<null>"); // hi
Console.WriteLine(NormalizeOrNull(null) ?? "<null>"); // <null>
[return: NotNullIfNotNull(nameof(input))]
static string? NormalizeOrNull(string? input) => input?.Trim();
Если параметр переименовывается, аргумент nameof обновляется при том же рефакторинге — атрибут не может устареть.
Квалифицированные имена
Для любого квалифицированного выражения nameof возвращает только последний идентификатор:
// For a qualified expression, nameof returns only the final identifier.
Console.WriteLine(nameof(System.Collections.Generic.List<int>)); // List
Console.WriteLine(nameof(Customer.Name)); // Name
Если вам нужно полное имя, используйте Type.FullName для экземпляра Type.
nameof предназначен для идентификаторов, а не путей.
Используйте nameof вместо строковых идентификаторов
В любом месте, где вы ссылаетесь на метод, свойство, параметр, тип или пространство имен по имени в коде, используйте nameof вместо строкового литерала. По сравнению с жестко закодированной строкой:
- Компилятор проверяет, существует ли символ. Опечатка приводит к ошибке сборки, а не к незаметному багу во время выполнения.
- Рефакторинг переименования автоматически обновляет результат. Жестко закодированные строки не синхронизируются.
- Результат представляет собой константу на этапе компиляции, поэтому во время выполнения дополнительные затраты отсутствуют.
Эта рекомендация применяется к сообщениям журнала, аргументам исключений, аргументам атрибутов, уведомлениям об изменении свойств и константам ключей сериализации, привязанным к имени члена.