聪明的事件访问器 - 在他们注册的线程上触发处理程序?

时间:2011-04-07 15:21:35

标签: c# multithreading events delegates dispatcher

刚刚有了一个想法,我以前没见过,想知道你们是否认为这是一个好主意,是否存在,任何常见的陷阱等等 - 以及如何实现它。

有几次我发现自己订阅了来自UI线程的事件,该事件将从不同的线程调用 - 例如,完成服务调用的通知。

'我'的想法是将当前Dispatcher与处理程序委托一起存储在add块中,然后当事件被'触发'时,执行一些额外的逻辑/检查以查看是否有一个与处理程序关联的调度程序,如果需要,还有Invoke

当然它只适用于Dispatcher的线程(或者与Forms相同的东西 - 我猜的是带消息泵的东西)。我想有用性和清洁度取决于事件订阅者是否应该担心调用处理程序的线程?


编辑:听起来这不是一件坏事 - 另外有人知道如何实施吗?使用Delegate.Combine如何在不同的Dispatcher上调用每个处理程序?您是否会将委托存储在List中的复合对象中,并在On(Whatever)方法中依次调用它们,还是有更好的东西?

...查看Reflector中的BackgroundWorker源代码,无需调用:

protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
{
    ProgressChangedEventHandler handler = (ProgressChangedEventHandler) base.Events[progressChangedKey];
    if (handler != null)
    {
        handler(this, e);
    }
}

除非我遗漏了什么?


然后BackgroundWorker使用AsyncOperation执行此操作。在事件访问器中,只为事件处理程序提供通用解决方案? BackgroundWorker可以通过它的工作方式逃脱,因为从客户端调用了一个方法 - 在更一般的情况下,你有权访问处理程序的线程的唯一时间是在事件访问器中? :)

2 个答案:

答案 0 :(得分:4)

据我所知,这正是BackgroundWorkerRunWorkerCompletedProgressChanged事件中正在做的事情。所以它不能坏 我找不到真正的证明,BackgroundWorker正在做这件事,我只是在某处读到它。当您google for it时,您会发现更多提示。如果有人可以提供链接,我会很高兴。

<强>更新
因为在BackgroundWorker中找到这种行为并不容易,所以我提供了我的分析:
BackgroundWorker正在使用AsyncOperation来举起活动。在此课程中,事件将发布到SynchronizationContext。只有这样才能执行方法OnProgressChangedOnRunWorkerCompleted。这意味着,这些方法已经在正确的线程上执行。

更详细地说,当调用RunWorkerAsync时会发生以下情况:

  1. AsyncOperation实例是通过AsyncOperationManager.CreateOperation创建的。这样可以保存当前SynchronizationContext。由于我们仍处于UI线程中,因此这是UI线程的上下文。
  2. 启动后台操作并调用私有方法WorkerThreadStart。此方法在后台线程中运行并执行OnDoWork,后者又会引发DoWork事件。这意味着,在{@ li>中,DoWork事件在
  3. 中引发
  4. OnDoWork完成后,PostOperationCompleted实例的AsyncOperation方法会被调用,AsyncOperation.Post会调用SynchronizationContext.Post,后者会调用OnRunWorkerCompleted,后者将间接调用UI线程上的ReportProgress
  5. 当调用AsyncOperation.Post时,会发生类似的事情:直接调用OnProgressChanged并在UI线程上调用{{1}}方法。
  6. AsyncOperationAsyncOperationManager是公开的,可用于在您的类中实现类似的行为。

答案 1 :(得分:0)

我已经使用Castle DynamicProxy做了类似的事情,它拦截了调用并对它们进行了IsInvokeRequired/Invoke