观察以下代码:
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnAsyncOperationCompleted;
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
现在假设我想等到bw
完成工作。这样做的正确方法是什么?
我的解决方案是这样的:
bool finished = false;
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += (sender, args) =>
{
OnAsyncOperationCompleted(sender, args);
finished = true;
});
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
int timeout = N;
while (!finished && timeout > 0)
{
Thread.Sleep(1000);
--timeout;
}
if (!finished)
{
throw new TimedoutException("bla bla bla");
}
但我不喜欢它。
我考虑过用finished
同步事件替换标志,在RunWorkerCompleted
处理程序中设置它并稍后阻止它,而不是执行 while-sleep 循环。
唉,这是错误的,因为代码可能在 WPF 或 WindowsForm 同步上下文中运行,在这种情况下,我会阻塞与处理程序运行相同的线程RunWorkerCompleted
,这显然不是很聪明的举动。
我想知道一个更好的解决方案。
谢谢。
编辑:
附言
- 为了澄清我的问题,故意设计了示例代码。我完全了解完成回调,但我想知道如何等到完成。那是我的问题。
- 我知道
Thread.Join
,Delegate.BeginInvoke
,ThreadPool.QueueUserWorkItem
, 等等...这个问题具体是关于BackgroundWorker
.
编辑2:
好的,我想如果我解释一下场景会容易得多。
我有一个单元测试方法,它调用一些异步代码,而这些代码最终会参与BackgroundWorker
我能够将完成处理程序传递给它的对象。所有代码都是我的,所以如果我愿意,我可以更改实现。但是,我不会替换BackgroundWorker
,因为它会自动使用正确的同步上下文,因此当在 UI 线程上调用代码时,会在同一个 UI 线程上调用完成回调,这非常好。
无论如何,单元测试方法有可能在 BW 完成工作之前就结束了,这是不好的。所以我希望等到 BW 完成并想知道最好的方法。
它还有更多部分,但整体情况或多或少像我刚刚描述的那样。