使用字符串常量通知属性更改

本文关键字:属性 通知 常量 字符串 | 更新日期: 2023-09-27 18:19:10

我正在使用一些现有的代码,并试图找出在实现INotifyPropertyChanged接口时使用属性名称的字符串常量的优势(如果有的话)。

例如:

/*
 * Why use this instead of string literal
 * in OnPropertyChanged below??
 */
public const string CustomerIdPropertyName = "CustomerId";
private int _customerId;
public int CustomerId
{
    get
    {
         return _customerId;
    }
    set
    {
         if (_cusomterId != value)
         {
              _customerId = value;
              OnPropertyChanged(CustomerIdPropertyName);
         }
    }
}

而不是:

private int _customerId;
public int CustomerId
{
    get
    {
         return _customerId;
    }
    set
    {
         if (_cusomterId != value)
         {
              _customerId = value;
              OnPropertyChanged("CustomerId");
         }
    }
}

使用字符串常量通知属性更改

两个版本同样容易出现输入错误。

如果你使用的是最近的。net版本,你的属性更改处理程序应该是这样的:

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
  var handler = this.PropertyChanged;
  if (handler != null)
  {
    handler(this, new PropertyChangedEventArgs(propertyName));
  }
}

那么你的属性看起来像这样:

private int _customerId;
public int CustomerId
{
    get
    {
         return _customerId;
    }
    set
    {
         if (_cusomterId != value)
         {
              _customerId = value;
              this.OnPropertyChanged();
         }
    }
}

这对编译器没有好处,因为两者最终都是一个常量。

我想象不出这样使用代码有什么真正的好处。这两种方法都很容易出现错别字,而且你不会在任何地方重用这个常量,所以它是没有意义的。

我很想看到新的nameof关键字在。net的下一个版本中实现。或者,如果可能的话,使用Marc Gravell建议的[CallerMemberName]更好。

nameof的使用将是有用的自定义计算属性(如在WPF中),没有自己的getter/setter。

要回答你的问题(试图找出优势):对于知道你的类型并等待特定属性更改的观察者来说,有一个优势

void Observe(Customer c)
{
    c.PropertyChanged += (s, e) => 
    {
        if (e.PropertyName == Customer.CustomerIdPropertyName)
        {
            MessageBox.Show("New id " + Customer.CustomerId);
        }
    }
}

如果你想继续:

使用属性选择器表达式来填充CustomerIdPropertyName可以避免输入错误。

你不需要它与nameof关键字(CTP)。如果你没有这种观察者,CalleMemberNameAttribute是最简单的方法。

我想这只是为了避免由拼写错误引起的错误,并尝试使代码更容易阅读。此外,如果你改变了属性的名称,这意味着改变const的值将对所有检查属性是否改变的代码起作用。例如,想象一下这样的代码:

public void Main()
{
    var obj = new ClassWithNotifier();
    obj.OnPropertyChanged += ObjectPropertyChanged;
    DoSomethingWithObj(obj);
}
private void ObjectPropertyChanged(string propertyName)
{
    switch (propertyName) {
        case ClassWithNotifier.CustomerIdPropertyName:
            // If the constant changes this will still work
            break;
        case "SomeOtherPropertyName":
            // If you change the property string that is passed here from 
            // your class ClassWithNotifier then this will now break
            break;
    }
}

在上面的例子中,不管常量的值是什么,代码都可以工作,如果你想在某个时候改变属性名,那么你只需要改变常量的值,一切都可以正常工作,而不需要找到我们正在检查名称的所有地方(显然,如果你想改变常量变量的名称,那么你仍然需要找到那些引用)。但是查找Public字段的引用要比在整个项目中查找魔术字符串容易)