在try/catch/finally中等待的好方法?

use*_*050 89 .net c# exception-handling async-await c#-5.0

我需要asynccatch块中调用一个方法,然后再次抛出异常(带有它的堆栈跟踪),如下所示:

try
{
    // Do something
}
catch
{
    // <- Clean things here with async methods
    throw;
}
Run Code Online (Sandbox Code Playgroud)

但不幸的是你无法await在一个catch或一个finally块中使用.我学会了它是因为编译器没有任何方法可以回到catch块中来执行你的await指令之类的东西......

我试图用来Task.Wait()替换await,我遇到了僵局.我在网上搜索了如何避免这种情况并找到了这个网站.

由于我无法更改async方法,也不知道它们是否使用ConfigureAwait(false),因此我创建了这些方法,这些方法Func<Task>在我们处于不同的线程(以避免死锁)并等待其完成时启动异步方法:

public static void AwaitTaskSync(Func<Task> action)
{
    Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}

public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
    return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}

public static void AwaitSync(Func<IAsyncAction> action)
{
    AwaitTaskSync(() => action().AsTask());
}

public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
    return AwaitTaskSync(() => action().AsTask());
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:你觉得这段代码还可以吗?

当然,如果你有一些改进或知道更好的方法,我正在听!:)

小智 169

您可以在catch块之外移动逻辑,并在需要时使用重新抛出异常ExceptionDispatchInfo.

static async Task f()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        await TaskThatFails();
    }
    catch (MyException ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }

    if (capturedException != null)
    {
        await ExceptionHandler();

        capturedException.Throw();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,当调用者检查异常的StackTrace属性时,它仍会记录TaskThatFails抛出内部的位置.

  • 保留 `ExceptionDispatchInfo` 而不是 `Exception` 有什么好处(如 Stephen Cleary 的回答)? (2认同)
  • 我可以猜测,如果你决定重新抛出`Exception`,你会失去以前的所有`StackTrace`? (2认同)

Adi*_*ter 54

您应该知道,自C#6.0以来,可以使用awaitin catchfinallyblocks,因此您实际上可以这样做:

try
{
    // Do something
}
catch (Exception ex)
{
    await DoCleanupAsync();
    throw;
}
Run Code Online (Sandbox Code Playgroud)

新的C#6.0功能,包括我刚才提到的功能,在这里列出或作为视频在这里.

  • @DavidRR.维基百科不具有权威性.就这一点而言,它只是数百万人中的另一个网站. (4认同)

Ste*_*ary 16

如果您需要使用async错误处理程序,我建议这样的事情:

Exception exception = null;
try
{
  ...
}
catch (Exception ex)
{
  exception = ex;
}

if (exception != null)
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

同步阻塞async代码(无论它运行的是什么线程)的问题是你同步阻塞.在大多数情况下,最好使用它await.

更新:由于您需要重新抛出,您可以使用ExceptionDispatchInfo.