我是否总是必须等待一次性对象的异步方法而不是返回其任务?

Do I always have to await on an Async method of a disposable object instead of returning its Task?

我似乎陷入了一个巨大的困境,经过数小时的调试后,我发现该进程超出了 RunGame1() 中的“使用”范围,并且任务在等待时从未完成。

async void Execute(object o)  // ICommand.Execute
{
    // fire and forget
    try
    {
        await RunGame2();  // RunGame1() fails to complete
    }
    finally
    { ... }
}

// This fails due to process going out of "using" scope and never completes
Task RunGame1()
{
    var info = new ProcessStartInfo("game.exe") { CreateNoWindow = true };
    using var process = new Process() { StartInfo = info };
    process.Start();
    return process.WaitForExitAsync();
}

// Have to await the Task inside the method
async Task RunGame2()
{
    var info = new ProcessStartInfo("game.exe") { CreateNoWindow = true };
    using var process = new Process() { StartInfo = info };
    process.Start();
    await process.WaitForExitAsync();
}

是否有解决此问题的模式,以便我可以 return 任务来保存编译器制作额外的状态机,或者它只是需要注意的事情?

这确实是一个常见的陷阱 - 我已经看到几个类似的错误。

简而言之:

  • 没有,你并不总是需要await一项任务,有时它可以积极地有利于避免异步机制的开销——尤其是在像 file/network IO 循环这样的紧凑代码中,but(这是一个很大的但是)
  • if 这意味着您正在逃离 try/finally 区域(其中还包括 usinglock ,尽管 async 代码中的 lock 存在其他更大的问题),那么 你需要考虑到这一点 ,这通常意味着“是的,你需要await"

如果有一个分析器在非async方法中发现Task[<T>]/ValueTask[<T>]return就好了,这样的区域中,因为它几乎总是一个错误,并且有几次不是(finally与返回的东西无关)它可能是压制。