与Dispose相关的Action<T>委托和事件处理程序的区别

5
我正在寻求架构建议,以及更深入地了解委托和Lambda表达式(除了需要修复一个真正的问题!)
我们通过PDA上的串口与设备(秤)交互的代码。我们连接视图以从设备接收数据。由于一次只有一个视图“连接”到我们的比例实例,因此我们使用类型为Action的属性来处理比例实例和视图之间的交互(而不是订阅事件)。然后,视图将该属性设置为从比例中获取值并修改UI的Lambda。
我们目前遇到的问题是在视图Dispose时。如果比例当前正在发送数据(并且我们在Action处理程序内部),当用户关闭视图时(此时我们强制执行Dispose,因为我们正在使用CF),应用程序会挂起:Action Lambda永远不会完成运行,并且在尝试关闭SerialPort时,比例实例的Dispose也会挂起。
1. 在这种情况下,类上的Action属性在处理方式上是否与事件有关键区别? 2. 根据日志详细信息,当视图调用Dispose时,代码位于Action Lambda内部(它修改了一些UI元素)。这两者都在UI线程上--它们怎么可能同时运行?昨晚我没有睡够吗? 3. 是否有任何人看到了一些不良的架构决策,应进行更正?
谢谢。如果描述不够清楚,我可以尝试在这里放一些代码示例。

2听起来像可能是可重入性问题? - Marc Gravell
2个回答

2

如果lambda表达式没有被用作表达式树,它就会转换成普通的委托,所以这不应该是问题所在。

但整个事情听起来像是死锁/并发问题。不要直接关闭串口,而是使用一个信号来标记操作处理程序的持续时间(很可能在不同线程中并发运行-再次检查),这样你就可以优雅地等待它终止后再关闭端口。


正如Reed Copsey在他的回答中所指出的那样,DataReceived事件确实是在一个辅助线程上触发的。我们按照Lucero的建议添加了信号,问题似乎已经得到解决。 - Steve
Steve,感谢您的跟进。很高兴建议对您有用。 - Lucero

1
  1. 不是的 - 事件只是一个委托,就像Action一样

  2. 它们不能在同一线程中同时运行 - 更可能的是您在单独的线程中处置,或者操作处理程序在单独的线程中运行。如果这是响应串口发生的情况,请注意串口事件发生在后台线程上。

  3. 从架构的角度来看,这里真的没有足够的信息来确定应该更改什么或不更改什么。话虽如此,我质疑为什么您不使用事件 - 使用“action”与使用事件处理程序相比真的没有优势,但后者听起来更清晰地符合思维模型,并且会更清楚地显示您的意图。


  1. 我原本以为端口事件是在后台线程上发生的,但我不需要调用Invoke来更新UI,所以我以为我错了。现在我对为什么不需要Invoke感到困惑。
  2. 懒惰和没有看到使用Action<T>时的好处。
- Steve
@Steve:你提到你在CF上工作-根据平台的不同,后台线程对UI的更新并不总是会引发异常,尤其是在CF上。然而,它们仍然不是受支持的操作,所以你仍然应该使用invoke。至于线程方面,请参考SerialPort.DataReceived:http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx "当从SerialPort对象接收到数据时,DataReceived事件将在一个辅助线程上触发"。 - Reed Copsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接