23

随着 .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));
    }
}

第三种也是最新的方法已(或即将)作为 .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));
}

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

4

2 回答 2

32

关于效率:直接使用字符串,由于字符串是在编译时由编译器注入的CallerMemberNameAttributenameof所以完全一样。不涉及反射。

我们可以看到,使用 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));
    }
}

由于在运行时所有选项都只是一个stringWPF 上下文没有问题。

关于方便:CallerMemberNameAttribute要求您有一个可选参数,而nameof没有,但nameof要求您指定属性,而CallerMemberNameAttribute没有。

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

于 2015-02-08T18:03:52.663 回答
7

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));
        }
   }
}
于 2015-02-08T19:31:02.617 回答