关于在 C# 中包装异步方法,我有一个奇怪的行为。
很难删除我的代码中有这种奇怪行为的部分,所以我做了一个测试项目来调查这种行为,这就是我所发现的。
我有一个测试类,它有一个异步方法,它只是另一个异步方法的包装器:(在我的原始代码中,它是一个包含 2 个对象的包装器类,它有包装器方法)
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
}
}
在我的测试程序中,我从异步事件处理程序运行以下代码:(在我的例子中是 Loaded 事件,因为我使用的是 WPF 窗口)
var test = new Test();
await Task.Delay(1000);
await test.Delay();
Task.Delay(1000).Wait();
test.Delay().Wait();
一切都很好,直到最后一行,它永远不会返回。
然后我尝试将测试类更改为以下内容,最后一行有效:
public class Test
{
public Task Delay()
{
return Task.Delay(1000);
}
}
我的问题是为什么第一种情况不起作用?
最佳答案
我详细描述了这种死锁情况 on my blog在 MSDN article 中.
默认情况下,当你await
一个任务时,它会捕获当前的“上下文”(SynchronizationContext.Current
,除非它是null
,在这种情况下,它会捕获 TaskScheduler.Current
)。当 async
方法恢复时,它会在该上下文中恢复。
在您的例子中,UI 上下文被捕获,并且您的 async
方法试图在延迟完成后在 UI 线程上恢复。但是,它无法恢复执行,因为 UI 线程被阻塞等待任务完成。
最好的解决方案是“一路”使用async
;换句话说,不要阻塞 async
代码。
关于c# - 包装异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22016446/