使用nameof运算符而不是CallerMemberNameAttribute来通知.NET 4.5.3中的属性更改有什么好处?

She*_*dan 22 c# callermembername c#-6.0 .net-4.6 nameof

随着.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));
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是在.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));
    }
}
Run Code Online (Sandbox Code Playgroud)

第三个也是最近的方法是(或将很快)作为.NET 4.5.3的一部分在C#6.0中引入; 该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));
}
Run Code Online (Sandbox Code Playgroud)

我自己的假设是,简单地传递字符串的原始的,更容易出错的方法将是最有效的,因为我只能想象其他两种方法使用某种形式的反射.但是,我真的很想知道其他两种方法中哪一种更有效,CallerMemberNameAttribute以及nameof在WPF上下文中使用属性和运算符之间是否存在任何差异.

i3a*_*non 29

关于效率:直接使用字符串,因为编译器在编译时注入字符串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));
    }
}
Run Code Online (Sandbox Code Playgroud)

本作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));
    }
}
Run Code Online (Sandbox Code Playgroud)

因为在运行时所有选项都只是一个stringWPF上下文没有问题.

关于便利性:CallerMemberNameAttribute要求您具有可选参数nameof而不nameof要求,但要求您指定属性CallerMemberNameAttribute而不要求.

我预测nameof会变得如此受欢迎,以至于使用它会更简单.


Pau*_*ado 6

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));
        }
   }
}
Run Code Online (Sandbox Code Playgroud)