Есть ли какое-либо преимущество в использовании оператора nameof вместо CallerMemberNameAttribute для уведомления об изменениях свойств в.NET 4.5.3?

С появлением.NET 4.5.3 разработчики WPF теперь имеют три (или более) способа уведомить INotifyPropertyChanged Интерфейс изменения свойств. По сути, мой вопрос заключается в том, какой из двух методов, представленных в.NET 4.5 и более поздних версиях, является более эффективным способом уведомления об изменениях свойств и имеет ли какой-либо из них преимущества при использовании в WPF?

Фон

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

public string TestValue
{
    get { return testValue; }
    set { testValue = value; NotifyPropertyChanged("TestValue"); }
}

protected virtual void NotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Второй метод был введен в.NET 4.5; CallerMemberNameAttribute:

public string TestValue
{
    get { return testValue; }
    set { testValue = value; NotifyPropertyChanged(); }
}

protected virtual void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Третий и самый последний метод был (или скоро будет) введен в C#6.0 как часть.NET 4.5.3; nameof Оператор:

public string TestValue
{
    get { return testValue; }
    set { testValue = value; NotifyPropertyChanged(nameof(TestValue)); }
}

protected virtual void NotifyPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Мое личное предположение состояло бы в том, что оригинальный, более подверженный ошибкам метод простой передачи строки был бы наиболее эффективным, поскольку я могу только представить, что два других метода используют некоторую форму отражения. Тем не менее, я действительно хочу выяснить, какой из двух других методов более эффективен и будет ли какая-либо разница между использованием CallerMemberNameAttribute атрибут и nameof оператор в контексте WPF.

2 ответа

Решение

Об эффективности: использование строки напрямую, CallerMemberNameAttribute, nameof все одинаковы, так как строка вводится компилятором во время компиляции. Там нет никакого отражения.

Мы можем видеть, что используя TryRoslyn, который производит это дляCallerMemberNameAttribute:

public string TestValue
{
    get { return this.testValue; }
    set { this.testValue = value; this.NotifyPropertyChanged("TestValue"); }
}
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
    if (this.PropertyChanged != null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

И это дляnameof:

public string TestValue
{
    get { return this.testValue; }
    set { this.testValue = value; this.NotifyPropertyChanged("TestValue"); }
}
protected virtual void NotifyPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Поскольку во время выполнения все параметры просто string нет проблем с контекстом WPF.

Об удобстве: CallerMemberNameAttribute требует, чтобы у вас был необязательный параметр nameof не но nameof требует указать свойство в то время как CallerMemberNameAttribute не делает.

Я предсказываю что nameof окажется настолько популярным, что его будет гораздо проще использовать.

CallerMemberNameAttribute может использоваться только в вызываемой функции для получения имени вызывающей функции.

nameof оператор выходит далеко за рамки этого. Может использоваться где угодно.

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

public string FullName
{
   get
   {
       return string.Format(
           "{0} {1}",
           this.firstName,
           this.lastName);
   }
}

public string FirstName
{
   get
   {
       return this.firstName;
   }
   set
   {
       if (value != this.firstName)
       {
           this.firstName = value;
           NotifyPropertyChanged(nameof(FirstName));
           NotifyPropertyChanged(nameof(FullName));
        }
   }
}

public string LasttName
{
   get
   {
       return this.lastName;
   }
   set
   {
       if (value != this.lastName)
       {
           this.lastName = value;
           NotifyPropertyChanged(nameof(LasttName));
           NotifyPropertyChanged(nameof(FullName));
        }
   }
}
Другие вопросы по тегам