使用 CodeContracts 强制执行 INotifyPropertyChanged 的正确实现 - “需要未经证实”
我正在寻找一种简单的方法来强制执行 INotifyPropertyChanged 的正确实现,即当引发 PropertyChanged 时,它必须引用实际定义的属性。我尝试使用 Microsoft 的新 CodeContract 工具执行此操作,但我不断收到警告“CodeContracts:需要未经验证”。这是我的代码...
public sealed class MyClass : INotifyPropertyChanged
{
private int myProperty;
public int MyProperty
{
get
{
return myProperty;
}
set
{
if (myProperty == value)
{
return;
}
myProperty = value;
OnPropertyChanged("MyProperty");
}
}
private void OnPropertyChanged(string propertyName)
{
Contract.Requires(GetType().GetProperties().Any(x => x.Name == propertyName));
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
有什么办法让它工作吗?
I'm looking for an easy way to enforce the correct implementation of INotifyPropertyChanged i.e. when PropertyChanged is raised it must reference a property that is actually defined. I tried doing this with the new CodeContract tools from Microsoft, but I keep getting the warning "CodeContracts: requires unproven". Here is my code...
public sealed class MyClass : INotifyPropertyChanged
{
private int myProperty;
public int MyProperty
{
get
{
return myProperty;
}
set
{
if (myProperty == value)
{
return;
}
myProperty = value;
OnPropertyChanged("MyProperty");
}
}
private void OnPropertyChanged(string propertyName)
{
Contract.Requires(GetType().GetProperties().Any(x => x.Name == propertyName));
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Is there anyway to get this to work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好的,首先,为此目的,我个人使用 MVVM 基础。这是一个仅调试构建的运行时检查,与您的几乎相同。
这可能是最简单的方法,但它有一定的缺点:您需要能够从某个基类继承,它只在运行时有效(尽管这在我的 wpf 经验中总是足够的),它看起来确实像一个“补丁”缺少静态检查。
对于这种情况,您有多种方法启用静态分析/静态工具:
至于CodeContracts,我认为它还不够成熟,无法处理静态分析中的此类检查。想象一下,它必须解析您的 lambda,了解如何因错误的
propertyName
而失败,找到对此方法的所有调用,找出所有可能的输入等。这只是一个错误的工具一种检查。Ok, first of all, for this purpose I personally use ObservableObject implementation from the MVVM foundation. It is a DEBUG-build only runtime check almost identical to yours.
It's probably the easiest way, but it has certain disadvantages: you need to be able to inherit from some base class, it only works in runtime (though this was always enough in my wpf-experience), it surely looks like a "patch" for a missing static check.
You have several ways to enable static analysis / static tools for this case:
As for the CodeContracts, I believe it is not yet mature enough to handle this kind of checks in static analysis. Imagine, it has to parse your lambda, understand how it can be failed by a wrong
propertyName
, find all calls to this method, figure out all possible inputs, etc. It is just a wrong instrument for that kind of check.我想你的意思是静态分析工具? (我希望运行时检查至少能够工作 - 并且您可能可以将其保留在调试版本中)。我怀疑静态分析是否能够看穿这一点 - GetType().GetProperties() 太复杂了,等等
。我对此表示怀疑... lambda(
Expression
)是一种选择,但它们比仅传递字符串要慢得多。I assume you mean with the static analysis tools? (I would expect the runtime check to work, at least - and you could presumably leave it in debug builds). I doubt that this is something that static analysis is going to be able to see through -
GetType().GetProperties()
is simply too complex, etc.In short; I doubt it... lambdas (
Expression
) are an option, but they are much slower than passing just a string.我过去这样做的方法是使用我们的好朋友 Lambda。通过使用表达式,我们可以将属性本身传递给 OnPropertyChanges 的实现,并使用表达式树来提取属性。这使您可以在编译时检查为其引发 PropertyChanged 事件的成员。
当然,表达式的使用完全取决于您需要什么类型的性能。
请参阅下面的代码片段:
The way I have done this in the past is to use our good friend Lambda. By using Expressions we can pass in the properties themselves to your implementation of OnPropertyChanges, and use the Expression tree to extract the property. This gives you compile time checking of the members you are raising the PropertyChanged event for.
Of course use of Expression will depend entirely on what type of performance you need.
See code snippet below: