Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免在发送通知时丢失收件人? 我的程序如何工作_C#_Multithreading_Events - Fatal编程技术网

C# 如何避免在发送通知时丢失收件人? 我的程序如何工作

C# 如何避免在发送通知时丢失收件人? 我的程序如何工作,c#,multithreading,events,C#,Multithreading,Events,我的后端有几个对象,它们具有PropertyChanged事件。更改某些属性时,将触发通知。在前端,我用WPF编写了GUI,几个属性直接绑定到WPF小部件 为了使GUI具有响应性,所有的计算都在额外的线程中完成 所以,一般来说,经典的WPF应用程序 错误 此代码发送通知,但在(*)处引发异常,因为PropertyChanged为null(是的,仅在检查null后) 问题: 我猜这是因为在WPF中重新绑定——在我的代码中我更改了发送方,所以WPF必须取消注册接收方并将其注册到新的发送方。异常很少被

我的后端有几个对象,它们具有PropertyChanged事件。更改某些属性时,将触发通知。在前端,我用WPF编写了GUI,几个属性直接绑定到WPF小部件

为了使GUI具有响应性,所有的计算都在额外的线程中完成

所以,一般来说,经典的WPF应用程序

错误 此代码发送通知,但在(*)处引发异常,因为PropertyChanged为null(是的,仅在检查null后

问题: 我猜这是因为在WPF中重新绑定——在我的代码中我更改了发送方,所以WPF必须取消注册接收方并将其注册到新的发送方。异常很少被抛出(我每~40000次执行就抛出一个异常,每个异常大致相当于发送方的一次更改),但它确实发生了


现在--如何正确地锁定PropertyChange,以便我可以检查null并将通知作为原子操作发送?我不想通过尝试和错误来实现这一点,因为我可以在每一次执行中发现副作用。

您可以在事件属性声明中拦截事件连接

private PropertyChangedEventHandler _propertyChanged;
public PropertyChangedEventHandler PropertyChanged
{
   add 
   { 
     // intercept here
     _propertyChanged += value; 
   }
   remove 
   { 
     // intercept here
     _propertyChanged -= value; 
   }
}

您可以在事件属性声明中拦截事件连接

private PropertyChangedEventHandler _propertyChanged;
public PropertyChangedEventHandler PropertyChanged
{
   add 
   { 
     // intercept here
     _propertyChanged += value; 
   }
   remove 
   { 
     // intercept here
     _propertyChanged -= value; 
   }
}

有一种模式可以解决此问题:

var evt = PropertyChanged;
if ( evt != null ) evt( this, new PropertyChangedEventArgs( name ) );

有一种模式可以解决此问题:

var evt = PropertyChanged;
if ( evt != null ) evt( this, new PropertyChangedEventArgs( name ) );

啊,等等,我收回我之前的评论——你建议我在更改接收者(“此处拦截”部分)和发送通知时添加锁,以便一次只能执行一个操作?不,我建议你可以检查事件何时注册/取消注册。引用你的话“如何正确锁定PropertyChange,以便我可以检查null并将通知作为原子操作发送?“我不明白你的意思。我唯一能想到的就是在这三个地方加上锁。正如你所说,你想到了其他的东西,所以请你在你的答案中添加更多的代码,它可以是伪代码。谢谢。也许我的答案是错的,尼克说得很有道理。我正在考虑如何了解更多关于事件取消/注册的信息,即堆栈跟踪等。但看起来这不是你一直在问的。啊,等等,我收回我之前的评论——你是否建议我在更改接收器(“此处拦截”部分)和发送通知时添加锁,所以一次只能执行一个操作?不,我建议您可以检查事件何时注册/取消注册。引用您的话“如何正确锁定PropertyChange,以便我可以检查null并将通知作为原子操作发送?”我不明白。我唯一能想到的就是在这三个地方加上锁。正如你所说,你想到了其他的东西,所以请你在你的答案中添加更多的代码,它可以是伪代码。谢谢。也许我的答案是错的,尼克说得很有道理。我正在考虑如何了解更多有关事件取消/注册的信息,即堆栈跟踪等。但看起来这不是您一直在问的问题。您确定您复制了值(接收器)而不仅仅是事件的引用吗?这是正确的解决方案。它复制委托(可以为空)。您的问题是,您正在读取两次字段(第一次要检查,第二次要调用),这是一个竞争条件。代理是不可变的,因此,一旦您有了对一个字段的引用,它就永远不会更改。如果在事件中添加或删除处理程序,则会创建一个新的委托实例。@macias:通过向对象引入一个新的引用,您不需要复制值,从而防止对象被删除GCed@Nick巴特勒,这部分我在任何资源中都找不到。感谢您的澄清,我很高兴解决方案如此简单,但也令人不安,那么您通常只会看到发送通知的错误示例。您确定您复制了值(接收者)而不仅仅是事件的引用吗?这是正确的解决方案。它复制委托(可以为空)。您的问题是,您正在读取两次字段(第一次要检查,第二次要调用),这是一个竞争条件。代理是不可变的,因此,一旦您有了对一个字段的引用,它就永远不会更改。如果在事件中添加或删除处理程序,则会创建一个新的委托实例。@macias:通过向对象引入一个新的引用,您不需要复制值,从而防止对象被删除GCed@Nick巴特勒,这部分我在任何资源中都找不到。感谢您的澄清,我很高兴解决方案如此简单,但也令人不安,那么您通常只会看到发送通知的错误示例。