C# 包装异步方法

C# 包装异步方法,c#,asynchronous,async-await,C#,Asynchronous,Async Await,关于在C#中包装异步方法,我有一种奇怪的行为 很难删掉代码中有这种奇怪行为的部分,因此我做了一个测试项目来调查这种行为,这就是我所发现的 我有一个测试类,它有一个异步方法,它只是另一个异步方法的包装器:(在我的原始代码中,它是一个包装器类,包含2个对象,它有包装器方法) 在我的测试程序中,我从一个异步事件处理程序运行以下代码:(在我的例子中是加载的事件,因为我使用的是WPF窗口) 一切都很好,直到最后一行,永远不会回来 然后,我尝试将测试类更改为以下内容,最后一行起作用: public clas

关于在C#中包装异步方法,我有一种奇怪的行为

很难删掉代码中有这种奇怪行为的部分,因此我做了一个测试项目来调查这种行为,这就是我所发现的

我有一个测试类,它有一个异步方法,它只是另一个异步方法的包装器:(在我的原始代码中,它是一个包装器类,包含2个对象,它有包装器方法)

在我的测试程序中,我从一个异步事件处理程序运行以下代码:(在我的例子中是加载的事件,因为我使用的是WPF窗口)

一切都很好,直到最后一行,永远不会回来

然后,我尝试将测试类更改为以下内容,最后一行起作用:

public class Test
{
    public Task Delay()
    {
        return Task.Delay(1000);
    }
}
我的问题是为什么第一个场景不起作用?

默认情况下,构建
wait
关键字是为了尽可能多地保持原始代码在原始线程上运行(或者至少在相同的“上下文”中运行)由于在
之前运行的代码等待
,例如,如果您以前在线程池中运行,则任何线程池线程都可以)

现在的情况是,所有原始代码在可以运行时都希望在UI线程上运行

但是您在
Wait
中阻塞了UI线程,因此无法在
async
方法中运行剩余的代码,从而完成外部
任务。也就是说,在
任务。Delay
任务完成后,您的方法中只剩下一点点代码要运行:

public class Test
{
    public async Task Delay()
    {
        await Task.Delay(1000);
        //<-- This "Code" needs to run before my Task is completed
    }
}
公共类测试
{
公共异步任务延迟()
{
等待任务。延迟(1000);

// 我详细描述了这个死锁场景

默认情况下,当您等待任务时,它将捕获当前“上下文”(
SynchronizationContext.current
,除非它是
null
,在这种情况下它捕获
TaskScheduler.current
)。当
async
方法恢复时,它将在该上下文中恢复

在您的情况下,会捕获UI上下文,延迟完成后,
async
方法正试图在UI线程上恢复。但是,它无法恢复执行,因为UI线程在等待任务完成时被阻塞


最好的解决方案是“一路”使用
async
;换句话说,不要阻塞
async
代码。

这不是“重载”,你可能是对的(这是我能想到的最好的术语),但是你能提供一个更好的术语吗?+1:好的,我正在编辑这个问题。这里理想的解决方案是不要使用
ConfigureAwait(false)
,但是不要等待异步操作。我可以看出你的观点,所以你更愿意使用第二种场景,即不将其标记为异步并返回被调用的异步方法的任务?但是如果我想调用多个异步方法呢?@reSPAWNed正确的解决方案在Stephen的回答中描述,而不是这一个。你应该uld使整个应用程序异步,而不是混合使用异步和同步方法。如果你这样做,你根本不会有这个问题。@Servy:这是一个有效的观点,但是如果混合使用异步和同步代码是错误的,那么为什么会有等待方法?或者换句话说,在什么情况下会使用等待方法@这主要是因为
任务
的第一次迭代主要是为了表示在线程池线程中执行的CPU限制的工作。它的定义后来扩展为表示任何异步操作。任务有时可以用于根本不使用异步的应用程序中,并且o他们在整个应用程序中完全同步地等待。关键是你可以做一个或另一个,你不应该混搭。
public class Test
{
    public Task Delay()
    {
        return Task.Delay(1000);
    }
}
public class Test
{
    public async Task Delay()
    {
        await Task.Delay(1000);
        //<-- This "Code" needs to run before my Task is completed
    }
}