微软应该已经实现了一些活泼的东西INotifyPropertyChanged,比如在自动属性中,只需指定{get; set; notify;} 我认为这样做很有意义。或者有什么并发症吗?
INotifyPropertyChanged
{get; set; notify;}
我们自己可以在我们的属性中实现类似“通知”的东西吗?是否有一个优雅的解决方案可以在您的类中实现,或者唯一的方法是在每个属性中 INotifyPropertyChanged 引发事件。PropertyChanged
PropertyChanged
如果不能,我们可以写一些东西来自动生成一段代码来引发PropertyChanged 事件吗?
不使用 postsharp 之类的东西,我使用的最小版本使用如下:
public class Data : INotifyPropertyChanged { // boiler-plate public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetField<T>(ref T field, T value, string propertyName) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } // props private string name; public string Name { get { return name; } set { SetField(ref name, value, "Name"); } } }
然后,每个属性都类似于:
private string name; public string Name { get { return name; } set { SetField(ref name, value, "Name"); } }
这不是很大;如果需要,它也可以用作基类。如果您想应用其他逻辑,返回 from 会告诉您它是否是空操作bool。SetField
bool
SetField
使用 C# 5 甚至更容易:
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null) {...}
可以这样调用:
set { SetField(ref name, value); }
编译器将"Name"自动添加。
"Name"
C# 6.0 使实现更容易:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
…现在使用 C#7:
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); protected bool SetField<T>(ref T field, T value,[CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } private string name; public string Name { get => name; set => SetField(ref name, value); }
而且,对于 C# 8 和 Nullable 引用类型,它看起来像这样:
public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = "") { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } private string name; public string Name { get => name; set => SetField(ref name, value); }