Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.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_Delegates_Dispatcher - Fatal编程技术网

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

C# 聪明的事件访问器-在它们注册的线程上触发处理程序?,c#,multithreading,events,delegates,dispatcher,C#,Multithreading,Events,Delegates,Dispatcher,我刚刚有了一个想法,我以前没见过,想知道你们是否认为这是一个好主意,它是否存在,是否有任何常见的陷阱等等,以及如何实施它 有好几次我发现自己从UI线程订阅了一个事件,该事件将从另一个线程调用——例如,服务调用完成的通知 “我的”想法是将当前的Dispatcher与处理程序委托一起存储在add块中,然后当事件被“激发”时,执行一些额外的逻辑/检查以查看是否有与处理程序关联的调度程序,并在必要时调用它 当然,它只能在具有调度程序的线程上工作(或者是具有消息泵的等价形式)。我想有用性和干净性取决于事件

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

有好几次我发现自己从UI线程订阅了一个事件,该事件将从另一个线程调用——例如,服务调用完成的通知

“我的”想法是将当前的
Dispatcher
与处理程序委托一起存储在
add
块中,然后当事件被“激发”时,执行一些额外的逻辑/检查以查看是否有与处理程序关联的调度程序,并在必要时调用它

当然,它只能在具有
调度程序的线程上工作(或者是具有消息泵的等价形式)。我想有用性和干净性取决于事件订阅者是否应该担心处理程序调用的线程


编辑:听起来这并不是一件坏事——另外,有人知道如何实现吗?例如,使用
Delegate.Combine
如何在不同的
调度程序上调用每个处理程序?您是将委托存储在
列表中的复合对象中,然后在
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
可以摆脱它的工作方式,因为从客户端调用了一个方法-在更一般的情况下,只有在事件访问器中才能访问处理程序的线程:)

据我所知,这正是
BackgroundWorker
在其
RunWorkerCompleted
ProgressChanged
事件中所做的。所以不会那么糟糕。
我找不到真正的证据,
BackgroundWorker
正在做这件事,我只是在某个地方读到了。当你开始时,你会发现更多的提示。如果有人能提供一个链接,我会很高兴

更新:
因为在BackgroundWorker中发现这种行为并不容易,所以我提供了我的分析:
BackgroundWorker
正在使用
AsyncOperation
来引发事件。在这个类中,事件被发布到
SynchronizationContext
。只有这样,才能执行方法
OnProgressChanged
OnRunWorkerCompleted
。这意味着,这些方法已经在正确的线程上执行

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

  • 通过
    AsyncOperationManager.CreateOperation
    创建一个
    AsyncOperation
    实例。这将保存当前的同步上下文。由于我们仍然在UI线程中,这是UI线程的上下文
  • 后台操作启动并调用私有方法
    WorkerThreadStart
    。此方法在后台线程中运行,并执行
    OnDoWork
    ,从而引发
    DoWork
    事件。这意味着,
    DoWork
    事件不是在UI线程中引发的
  • OnDowWork
    完成后,执行
    AsyncOperation
    实例的
    PostOperationCompleted
    方法,该方法依次调用
    AsyncOperation.Post
    ,该方法调用
    SynchronizationContext.Post
    ,该方法反过来将间接调用UI线程上的
    OnRunWorkerCompleted
  • 调用
    ReportProgress
    时,会发生类似的情况:
    AsyncOperation.Post
    直接被调用,并将在UI线程上调用
    OnProgressChanged
    方法

  • 和是公共的,可以用于在类中实现类似的行为。

    据我所知,这正是
    BackgroundWorker
    在其
    RunWorkerCompleted
    ProgressChanged
    事件中所做的。所以不会那么糟糕。
    我找不到真正的证据,
    BackgroundWorker
    正在做这件事,我只是在某个地方读到了。当你开始时,你会发现更多的提示。如果有人能提供一个链接,我会很高兴

    更新:
    因为在BackgroundWorker中发现这种行为并不容易,所以我提供了我的分析:
    BackgroundWorker
    正在使用
    AsyncOperation
    来引发事件。在这个类中,事件被发布到
    SynchronizationContext
    。只有这样,才能执行方法
    OnProgressChanged
    OnRunWorkerCompleted
    。这意味着,这些方法已经在正确的线程上执行

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

  • 通过
    AsyncOperationManager.CreateOperation
    创建一个
    AsyncOperation
    实例。这将保存当前的同步上下文。由于我们仍然在UI线程中,这是UI线程的上下文
  • 后台操作启动并调用私有方法
    WorkerThreadStart
    。此方法在后台线程中运行,并执行
    OnDoWork
    ,从而引发
    DoWork
    事件。这意味着,
    DoWork
    事件不是在UI线程中引发的
  • OnDoWork
    完成后,执行
    AsyncOperation
    实例的
    PostOperationCompleted
    方法,该方法依次调用
    AsyncOperation.Post
    它调用
    SynchronizationContext.Post