Есть ли какая-либо польза от использования оператора nameof вместо CallerMemberNameAttribute для уведомления изменений свойств в .NET 4.5.3?
С появлением .NET 4.5.3 разработчики WPF теперь имеют три (или более) способа уведомления INotifyPropertyChanged
Interface изменения свойств. В основном, мой вопрос: какой из двух методов, введенных в .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));
}
}
Третий и самый последний метод был (или скоро будет) представлен в С# 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.
Ответы
Ответ 1
Об эффективности: использование строки напрямую, 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
окажется настолько популярным, что было бы гораздо проще использовать его вместо этого.
Ответ 2
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));
}
}
}