简体   繁体   English

C#INotifyPropertyChanged处理程序

[英]C# INotifyPropertyChanged handler

I am starting to read about MVVM and one pattern I see a lot is: 我开始阅读有关MVVM的内容,我看到的一个模式是:

public event PropertyChangedEventHandler PropertyChanged;
//.....

PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
    var e = new PropertyChangedEventArgs(propertyName);
    handler(this, e);
}

Why to bother to declare this handler variable? 为什么要费心声明这个handler变量? It just looks to me as complicating code unnecessarily, but I can see this even at Microsoft's own tutorials, why not to just use it as: 它只是让我觉得不必要的复杂代码,但我甚至可以在微软自己的教程中看到这一点,为什么不把它用作:

if (this.PropertyChanged != null)
{
    var e = new PropertyChangedEventArgs(propertyName);
    this.PropertyChanged(this, e);
}

Storing off the PropertyChanged event is for thread-safety. 存储PropertyChanged事件是为了线程安全。 In fact, you should technically be doing this with all your events. 事实上,你应该在技术上对所有事件这样做。

The assignment creates a copy of the event and its handlers (not a reference, which would be useless), which means you avoid the scenario where the event handler is set to null right after it passes the null check. 赋值创建事件及其处理程序的副本(不是引用,这将是无用的),这意味着您可以避免事件处理程序在通过null检查后立即设置为null This avoids a potential race condition that would throw a NullReferenceException. 这避免了可能引发NullReferenceException的竞争条件。

In reality, the UI isn't setting that property to null very often, if at all. 实际上,如果有的话,UI不会经常将该属性设置为null。 To be safe however, and use good practice, you should assign the handler off. 但是为了安全起见并使用良好实践,您应该关闭处理程序。

I just wanted to add a couple of points to BradleyDotNET's answer. 我只想为BradleyDotNET的答案添加几点。

In his book CLR via C#, Jeffrey Richter points out that the pattern is still not guaranteed to be thread-safe, because the compiler could optimize away the local variable (although the current version of the compiler does not make this optimization). 在他的书CLR via C#中,Jeffrey Richter指出该模式仍然不能保证是线程安全的,因为编译器可以优化掉局部变量(尽管当前版本的编译器没有进行这种优化)。 He recommends using Volatile.Read to be technically correct: 他建议使用Volatile.Read在技​​术上是正确的:

PropertyChangedEventHandler handler = Volatile.Read(ref PropertyChanged);
if (handler != null)
{
    var e = new PropertyChangedEventArgs(propertyName);
    handler(this, e);
}

In reality though, the other pattern is so widely used that Microsoft would very likely never make a change to the compiler that would break so many applications. 实际上,另一种模式被如此广泛地使用,以至于微软很可能永远不会对编译器进行更改,从而打破这么多应用程序。


One other point, is that you can actually add an empty dummy delegate to your events, like below: 另一点是,您实际上可以为事件添加一个空的虚拟委托 ,如下所示:

public event PropertyChangedEventHandler PropertyChanged = delegate { };

This means you don't have to worry about any null checking, because the event has at least one handler attached to start with. 这意味着您不必担心任何空检查,因为事件至少有一个附加的处理程序。 This practice is controversial, though, since it would seem to incur a performance penalty (in theory you add an extra invocation to every event call). 但是,这种做法存在争议,因为它似乎会导致性能损失(理论上,您会为每个事件调用添加额外的调用)。 Personally I avoid using it, as I would rather suffer more bloated code than bloated runtime performance. 我个人避免使用它,因为我宁愿遭受比膨胀的运行时性能更臃肿的代码。


This blog post by Eric Lippert on the topic is a good read. Eric Lippert关于这个主题的博客文章很好读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM