Статьи

NameOf (C # 6)

C # 6


Хотите узнать о других возможностях C # 6?
Ознакомьтесь с полным списком статей и исходного кода на 
GitHub

nameof — фантастический кусок  синтаксического сахара  в C # 6, который призван решить главную проблему: волшебные струны. Волшебная строка — это тип строки в вашем приложении, который не связан с вводом / выводом, а скорее является маркером или используется для некоторого сравнения, например, вы можете выполнить проверку ролей с помощью чего-то похожего на это:

if (role == "admin")
{
}

Проблема с этой строкой «admin» в том, что компилятор не проверяет ее. Это означает, что если вы неправильно наберете содержимое строки, вы не узнаете, что это неправильно, пока не произойдет сбой приложения. Вторая проблема с волшебной строкой заключается в том, что инструменты рефакторинга обычно не работают с ними, поэтому, если вы изменили «admin» на «administrator» в одном месте, инструменты не смогут найти и обновить все строки в вас. приложение и ваше приложение снова ломается при запуске.

Много времени вы можете очистить это с помощью  счетчиков  или объектов. Например, мы можем улучшить наш ролевый сценарий, но сверяясь с перечислителем:

if (role == Roles.admin.ToString())
{
}

Это больше не страдает от двух проблем, перечисленных выше

Члены и Волшебные Струны

Проблема остается с волшебными строками, которые ссылаются на элементы (поля, свойства, методы, типы и т. Д.) Вашего кода. В этом первом примере у нас есть волшебная строка, указывающая на свойство Age:

public int Age
{
    get { return age; }
    set
    {
        age = value;
        RaisePropertyChanged("Age");
    }
}

Для второго примера у нас есть волшебная строка, указывающая на класс Track:

var type = Type.GetType("Track");

И, наконец, наш третий пример — проверка поля на нулевое значение и создание исключения, если необходимо, с правильным именем поля:

private void RaisePropertyChanged(string propertyChanged)
{
    if (propertyChanged == null)
    {
        throw new ArgumentNullException("propertyChanged");
    }

    // do stuff
}

Все эти примеры страдают от тех же самых двух проблем, перечисленных с волшебными строками, но до сих пор не было способа эффективно их очистить.

Имя

Цель нового ключевого слова nameof — решить этот конкретный тип магической строки, то есть тех, которые ссылаются на элементы в коде. Используя nameof, мы можем изменить приведенные выше примеры на следующие:

// example 1
public int Age
{
    get { return age; }
    set
    {
        age = value;
        RaisePropertyChanged(nameof(Age));
    }
}

// example 2
var type = Type.GetType(nameof(Track));

// example 3
private void RaisePropertyChanged(string propertyChanged)
{
    if (propertyChanged == null)
    {
        throw new ArgumentNullException(nameof(propertyChanged));
    }

    // do stuff
}

Обратите внимание, что мы полностью удалили строки! Это означает, что если вы неправильно наберете имя члена во время компиляции, вы получите ошибку!

образ

Теперь мы также получаем ПОЛНУЮ поддержку рефакторинга, поскольку Visual Studio и другие инструменты рефакторинга могут получить информацию, необходимую для идентификации ее члена, и заменить / переименовать по мере необходимости.

Больше сахара

Как упоминалось в начале, это всего лишь случай синтаксического сахара, компилятор делает для нас хитрые трюки и генерирует немного другой код. Все, что делает nameof — это инструктирует компилятор преобразовывать элемент в строку, поэтому выводимый код остается прежним со строками.

Я хочу порекомендовать   веб-сайт TryRosyln, который является FANTASTIC, чтобы экспериментировать с C # 6, а также показывает вам декомпилированный код рядом, в основном показывая, как работает синтаксический сахар:

образ

Что это выводит?

В первом наборе примеров мы рассмотрели простые члены, но что, если у нас есть что-то более сложное, например, пространство имен или класс и свойство. В этих случаях он будет выводить последнюю часть каждый раз:

nameof(Track.Band); // Class.Property - outputs: Property, in this case 'Band'
nameof(System.Configuration); // Namespace - outputs: Last namespace, in this case 'Configuration'
nameof(List); // List + Generics: outputs: The type of the object, in this case 'List' <
nameof(this.field); // this keyword + field - outputs the field name 'field'

Что не поддерживается

nameof не является решением для всего в .NET, и есть много вещей, которые не будут работать. Вот некоторые примеры:

nameof(f()); // where f is a method - you could use nameof(f) instead
nameof(c._Age); // where c is a different class and _Age is private. Nameof can't break accessor rules.
nameof(List<>); // List<> isn't valid C# anyway, so this won't work
nameof(default(List<int>)); // default returns an instance, not a member
nameof(int); // int is a keyword, not a member- you could do nameof(Int32)
nameof(x[2]); // returns an instance using an indexer, so not a member
nameof("hello"); // a string isn't a member
nameof(1+2); // an int isn't a member

Это замена для CallerMemberName?

Я написал о фантастической функции .NET 4.5 под названием  CallerMemberName . Напомним, это способ приписать параметр метода и заставить во время выполнения изменить значение этого параметра на имя вызывающего члена. В следующем примере вывод будет «Main», соответствующий имени вызывающего метода:

private static void Main(string[] args)
{
    WhoCallsMe(); 
}

static void WhoCallsMe([CallerMemberName] string caller = "")
{
    Console.WriteLine(caller);
}

Это похоже на nameof, но есть некоторые фундаментальные различия, наиболее важно nameof в COMPILE TIME, а CallerMemberName в RUNTIME. Это означает, что этот метод в примере может работать с несколькими вызывающими; то есть я мог бы взять приведенный выше пример и вызвать другого члена, и он выведет правильное имя звонящего. Нет никакого способа сделать это с помощью nameof, которое в основном является жестко закодированными значениями. Существует некоторое перекрытие функциональности, а в некоторых случаях, например, XAML + RaisePropertyChanged, где вы можете выбрать один или другой на основе вкуса, но эти две части функциональности имеют свои различия, и бывают случаи, когда CallerMemberName является действительно единственным вариантом.