【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
Microsoft应该为INotifyPropertyChanged
实现了一些简单的功能,例如在自动属性中,只需指定{get; set; notify;}
{get; set; notify;}
{get; set; notify;}
我认为这样做很有意义。 还是有任何并发症要做?
我们自己可以在属性中实现“通知”之类的功能吗? 是否存在用于在您的类中实现INotifyPropertyChanged
的优雅解决方案,或者唯一的方法是通过在每个属性中引发PropertyChanged
事件。
如果不能,我们可以写一些东西来自动生成引发PropertyChanged
事件的代码吗?
#1楼
从.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
#2楼
我实际上还没有机会自己尝试一下,但是下一次我要建立一个对INotifyPropertyChanged有很高要求的项目时,我打算编写一个Postsharp属性,该属性将在编译时注入代码。 就像是:
[NotifiesChange]
public string FirstName { get; set; }
会变成:
private string _firstName;
public string FirstName
{
get { return _firstname; }
set
{
if (_firstname != value)
{
_firstname = value;
OnPropertyChanged("FirstName")
}
}
}
我不确定这在实践中是否可行,我需要坐下来尝试一下,但我不知道为什么不这样做。 对于需要触发多个OnPropertyChanged的情况,我可能需要使其接受某些参数(例如,如果我在上面的类中具有FullName属性)
目前,我在Resharper中使用自定义模板,但是即使那样,我也厌倦了我所有的属性太长了。
嗯,快速的Google搜索(我在写这篇文章之前就应该这样做)表明,至少有一个人在这里之前做了类似的事情。 不完全是我的初衷,但足够接近以证明该理论是好的。
#3楼
在不使用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
返回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([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}
#4楼
我真的很喜欢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;
}
#5楼
在这里查看: http : //dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
它是用德语编写的,但是您可以下载ViewModelBase.cs。 cs文件中的所有注释均以英语编写。
使用此ViewModelBase-Class可以实现类似于众所周知的Dependency Properties的可绑定属性:
public string SomeProperty
{
get { return GetValue( () => SomeProperty ); }
set { SetValue( () => SomeProperty, value ); }
}
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3151589