使用MVVM,我总是会看到这两种属性的方法:
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
和
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
NotifyPropertyChanged(m => m.MyProperty);
}
}
第一个使用硬编码字符串NotifyPropertyChanged,第二个使用lambda表达式NotifyPropertyChanged。我不想创建一个辩论,询问什么是更好的解决方案,但我想了解这两个解决方案之间的差异是什么。使用其中一个的后果是什么?
如果我错了,请纠正我,但lambda表达式解决方案应该使用更多内存,并且应该比硬编码字符串慢,因为基类的NotifyPropertyChanged方法使用委托和反射。但硬编码的字符串解决方案可能会创建愚蠢的错误,因为它是一个字符串,没有什么可以告诉我我正确写了它。
答案 0 :(得分:3)
第二个表达式会在属性名称更改时生成编译器错误,或者会自动更改(通过VS或ReSharper中的重命名支持)。
基本上,您获得了对属性名称的编译器支持。提供给通知的错误名称意味着数据绑定会中断。使用字符串名称,这种破坏将是沉默的。
在一个小的用户界面中,我认为选择是无关紧要的,但是在一个包含大量UI层的大型应用程序中,从长远来看,对bug的额外支持可以自行解决。
性能不会有问题更慢,不要忘记,绑定是反射驱动的。一如既往,表现是相对的。硬编码版本在技术上会更快,因为它不需要反映元数据中的属性名称。多快了,我不确定。
答案 1 :(得分:1)
不是为每个属性重复NotifyPropertyChanged的代码,而是觉得下面的代码更清晰
在ViewModel Base中创建一个Set方法
protected bool Set<T>(Expression<Func<T>> selectorExpression, ref T field, T value)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
RaisePropertyChanged(selectorExpression);
return true;
}
并将其用作
string title;
public string Title
{
get { return title; }
set { Set(() => Title, ref title, value); }
}
答案 2 :(得分:0)
我在实现INotifyPropertyChanged的基类中使用以下方法,它非常简单方便:
public void NotifyPropertyChanged()
{
StackTrace stackTrace = new StackTrace();
MethodBase method = stackTrace.GetFrame(1).GetMethod();
if (!(method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
{
throw new InvalidOperationException("The NotifyPropertyChanged() method can only be used from inside a property");
}
string propertyName = method.Name.Substring(4);
RaisePropertyChanged(propertyName);
}