Есть ли какое-либо преимущество в использовании оператора 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));
}
}
}