使用 nameof 运算符而不是 CallerMemberNameAttribute 来通知 .NET 4.5.3 中的 属性 更改有什么好处吗?
Is there any benefit of using the nameof operator instead of the CallerMemberNameAttribute to notify property changes in .NET 4.5.3?
随着 .NET 4.5.3 的出现,WPF 开发人员现在可以通过三种(或更多)方式通知 INotifyPropertyChanged
Interface 属性 更改。基本上,我的问题是 从 from.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));
}
}
作为 .NET 4.5.3 的一部分在 C#6.0 中引入了第三种也是最新的方法; nameof
Operator:
public string TestValue
{
get { return testValue; }
set { testValue = value; NotifyPropertyChanged(nameof(TestValue)); }
}
protected virtual void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
我自己的假设是,简单地传递字符串的原始的、更容易出错的方法是最有效的,因为我只能想象其他两种方法使用某种形式的反射。但是,我真的很想知道其他两种方法中哪一种更有效,以及在 WPF 上下文中使用 CallerMemberNameAttribute
属性和 nameof
运算符之间是否真的有任何区别。
关于效率:直接使用字符串,CallerMemberNameAttribute
,nameof
完全一样,因为字符串是编译器在编译时注入的。没有反射。
我们可以看到使用 TryRoslyn produces this for 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));
}
}
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));
}
}
}
随着 .NET 4.5.3 的出现,WPF 开发人员现在可以通过三种(或更多)方式通知 INotifyPropertyChanged
Interface 属性 更改。基本上,我的问题是 从 from.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));
}
}
作为 .NET 4.5.3 的一部分在 C#6.0 中引入了第三种也是最新的方法; nameof
Operator:
public string TestValue
{
get { return testValue; }
set { testValue = value; NotifyPropertyChanged(nameof(TestValue)); }
}
protected virtual void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
我自己的假设是,简单地传递字符串的原始的、更容易出错的方法是最有效的,因为我只能想象其他两种方法使用某种形式的反射。但是,我真的很想知道其他两种方法中哪一种更有效,以及在 WPF 上下文中使用 CallerMemberNameAttribute
属性和 nameof
运算符之间是否真的有任何区别。
关于效率:直接使用字符串,CallerMemberNameAttribute
,nameof
完全一样,因为字符串是编译器在编译时注入的。没有反射。
我们可以看到使用 TryRoslyn produces this for 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));
}
}
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));
}
}
}