有更好的方法存在吗?
微软应该为INotifyPropertyChanged
实现一些动作,就像在自动属性中一样,只需指定{get; set; notify;}
{get; set; notify;}
{get; set; notify;}
我认为这样做很有意义。 或者有什么并发症可以做到吗?
我们是否可以在我们的房产中实施类似“通知”的内容? 是否有在您的类中实现INotifyPropertyChanged
的优雅解决方案,或者唯一的方法是通过在每个属性中引发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"); }
}
这不是很大; 如果你愿意,它也可以用作基类。 SetField
的bool
返回告诉你它是否是空操作,以防你想应用其他逻辑。
或者更容易使用C#5:
protected bool SetField<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{...}
这可以这样调用:
set { SetField(ref name, value); }
编译器将使用它自动添加"Name"
。
C#6.0使实现更简单:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
...现在用C#7:
private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}
从.Net 4.5开始,最后有一种简单的方法可以做到这一点。
.Net 4.5引入了一个新的主叫信息属性。
private void OnPropertyChanged<T>([CallerMemberName]string caller = null) {
// make sure only to call this if the value actually changes
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(caller));
}
}
向函数添加一个比较器也是一个好主意。
EqualityComparer<T>.Default.Equals
这里和这里有更多的例子
另请参阅来电者信息(C#和Visual Basic)
我非常喜欢Marc的解决方案,但我认为它可以稍微改进以避免使用“魔术串”(不支持重构)。 而不是使用属性名称作为字符串,很容易使其成为lambda表达式:
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, () => Name); }
}
只需将以下方法添加到Marc的代码中,它就可以实现这一点:
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(selectorExpression);
return true;
}
顺便说一句,这是受此博客文章更新网址的启发
链接地址: http://www.djcxy.com/p/40743.html