使用.NET 4.5.3中nameof运算符与使用CallerMemberNameAttribute通知属性更改相比,有什么好处吗?

24

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

我个人的假设是最原始、错误率更高的传递字符串的方法是最有效的,因为我只能想象另外两种方法使用了某种形式的反射。然而,我非常想知道另外两种方法中哪一种更有效,以及在 WPF 上使用 CallerMemberNameAttribute 属性和 nameof 运算符是否会有任何区别。


1
第三种也是最新的方法是(或将很快)作为.NET 4.5.3的一部分引入C#6.0; 即nameof运算符。严格来说,nameof是一种语言特性而不是框架的一部分。 - Leonid Vasilev
2个回答

33

关于效率:直接使用字符串、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));
    }
}

由于在运行时,所有选项都只是一个字符串,因此WPF上下文没有问题。

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

我预测,nameof 将变得非常流行,使用它会更加简单。


1
为什么 nameof 会变得如此流行?使用 CallerMemberNameAttribute 就容易多了,只需要用一次,或者通常至少比每个属性都要使用的 nameof 要少。我不理解这些趋势……你能解释一下吗? - El Mac
@ElMac 的 nameof 已经在许多场景中变得流行起来...不仅仅是为了获取调用者的名称。越来越多的人知道它并在各个地方使用它,因此在这里也使用它更加简单。 - i3arnon

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));
        }
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接