我应该在值更改或调用 set 时引发 INotifyPropertyChanged 吗?

Should I raise INotifyPropertyChanged when the value changes or when set has been called?

实现INotifyPropertyChanged时,PropertyChanged应该只在n != value时被调用,还是应该因为调用了set才被调用?

我在这里寻找的是一个行业标准建议(如果存在这样的东西)对于哪个实施更好以及为什么。

示例 1 - 说明了 "dumb" 事件引发策略

class Person : INotifyPropertyChanged
{
    private string name;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        get
        {
            return name;
        }

        set
        {
            name = value;
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
        }
    }
}

示例 1 的用例

Person p = new Person();

p.Name = "John"; // ProperyChanged fired
p.Name = "John"; // ProperyChanged fired

示例 2 - 说明了 "clever" 事件引发策略

class Person : INotifyPropertyChanged
{
    private string name;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        get
        {
            return name;
        }

        set
        {
            if(name != value)
            {
                name = value;
                PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
            }
        }
    }
}

示例 2 的用例

Person p = new Person();

p.Name = "John"; // ProperyChanged fired
p.Name = "John"; // ProperyChanged ignored as name == value

注意示例 2 中的 if(name != value),它只允许更改值,并且当传入值与现有值不匹配时发生 ProperyChanged 事件。

documentation of INotifyPropertyChanged表示接口的用途是

Notifies clients that a property value has changed.

这显然指的是 "property value" 变化。文档页面上的示例也使用示例 2 中的模式。

如接口名称所示,INotifyPropertyChanged,根据 msdn:

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.

最好只在更改值时触发事件。

https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx

典型的实现模式类似于:

public string Foo
{
    get { return _foo; }
    set
    {    
        if (string.Equals(_foo, value)) return;

        _foo= value;
        OnPropertyChanged();
    }
}

顺便说一下,这也是 ReSharper 的约定,可以在这里找到; https://www.jetbrains.com/help/resharper/2016.1/Coding_Assistance__INotifyPropertyChanged_Support.html

附带说明:仅在更改的值上触发将保护您在更新从其他值计算的值时免受循环依赖。

示例: 考虑以下代码:

public string DependentFoo
{
    get { return _foo; }
    set
    {    
        if (string.Equals(_foo, value)) return;

        _foo= value;

        //if some condition:
        DependentBar = "";
        OnPropertyChanged();
    }
}

public string DependentBar
{
    get { return _bar; }
    set
    {    
        if (string.Equals(_bar, value)) return;

        _bar = value;

        //if some condition:
        DependentFoo = "";
        OnPropertyChanged();
    }
}

虽然这不是一个很好的例子,但我想你会明白这一点的。

没有 "right" 的方法。这完全取决于您需要它做什么。 例如:

如果您只需要更新 GUI,那么我会说在 属性 实际上没有更改时调用 PropertyChanged 是不必要的。但是,如果您想将该事件用于其他目的(例如日志记录或类似的东西),那么它绝对是一个解决方案。