C# 对notify属性使用字符串常量已更改

C# 对notify属性使用字符串常量已更改,c#,wpf,inotifypropertychanged,C#,Wpf,Inotifypropertychanged,我正在使用一些现有代码,并试图找出在实现INotifyPropertyChanged接口时使用字符串常量作为属性名称的优势(如果有的话) 举个例子: /* * Why use this instead of string literal * in OnPropertyChanged below?? */ public const string CustomerIdPropertyName = "CustomerId"; private int _customerId; public in

我正在使用一些现有代码,并试图找出在实现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();
         }
    }
}
然后,您的属性如下所示:

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

而且您不会遇到任何键入错误的问题。

在编译器方面没有任何优势,因为两者最终都是一个常量值

我无法想象这样使用代码有什么真正的优势。不管是哪种方式,都很容易打错,而且你不会在任何事情上重复使用这个常量,所以它是毫无意义的

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

当自定义计算属性(例如WPF)没有自己的getter/setter时,使用
nameof
将非常有用。

回答您的问题(试图找出优势):对于了解您的类型并等待特定属性更改的观察者来说,这是一个优势

void Observe(Customer c)
{
    c.PropertyChanged += (s, e) => 
    {
        if (e.PropertyName == Customer.CustomerIdPropertyName)
        {
            MessageBox.Show("New id " + Customer.CustomerId);
        }
    }
}
如果你想走得更远:

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


您不需要将其与
nameof
关键字(CTP)一起使用。如果你没有这样的观察者,
callembernameattribute
是最简单的方法。

我想这只是为了避免拼写错误引起的错误,并尝试让代码更容易阅读。此外,如果更改属性的名称,则意味着更改const的值将适用于检查属性是否已更改的所有代码。e、 g.想象一下这个代码:

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

在上面的例子中,不管常量的值是多少,代码都会起作用,如果您想在某个时候更改属性名称,那么您只需要更改常量值,所有内容都会起作用,而不必在检查名称的任何地方查找(显然,如果您还想更改常量变量的名称,那么仍然需要查找这些引用,但是查找公共字段的引用要比在整个项目中搜索魔术字符串更容易)

没有理由使用常量。它们在功能上是相同的。您的IDE可以帮助您键入
CustomerIdPropertyName
,这是我认为唯一的优势。@user2348184嗯,他们是否从其他地方引用了该名称?可能是
开关(e.PropertyName){…}
或类似的?
[CallerMemberName]
在这种情况下可以很好地工作;不需要从内部而不是外部工作的
nameof
。是的,但是将要侦听此事件的大多数代码都是类似于UI元素的东西-它们不关心实际名称,只需要执行
TypeConverter.GetProperties(…)[e.PropertyName]
或similar@MarcGravell:仅当从属性(-setter)内调用
OnPropertyChanged
时有效。对于计算属性,通常情况下不存储任何值,也不存在任何setter,但知道它们何时更改,从而从其他位置触发属性更改事件。@O.R.Mapper true,truen如果属性没有setter,而是在getter中计算,例如使用外部模型?@johanneslink取决于外部模型。您需要找到一种方法在外部数据更改时获得通知,然后自己调用
this.OnPropertyChanged(“YourPropertyName”);
。@nvoigt但是我不能使用CallerMemberName,因为调用OnPropertyChanged()时我不在属性的设置程序中。我的观点是:在我看来,CallerMemberName仅在属性与setter一起使用时才起作用。在所有其他情况下,我读到的原始问题仍然没有得到回答:“我们是否应该将属性名称提取为常量?”@johanneslink由于这是一个非常特殊的情况,在我不得不使用它的一两次中,普通字符串工作得很好。这是一个“视情况而定”的情况:)如果你想从其他代码钩住变更处理程序,一个常量就可以了,如果它只是WPF/GUI,那么硬编码字符串就足够了。