1. ホーム
  2. c#

[解決済み] try/catch/finallyでawaitの良い解決策?

2023-02-05 18:10:21

質問

私は async メソッドを呼び出す必要があります。 catch ブロックを作成し、例外(スタックトレース付き)を再度投げるようにします。

try
{
    // Do something
}
catch
{
    // <- Clean things here with async methods
    throw;
}

しかし、残念ながら await の中で catch または finally というブロックがあります。これは、コンパイラが catch ブロックの後にあるものを実行するために await の後にあるものを実行します。

を使おうとしたのですが Task.Wait() を置換するために await を実行すると、デッドロックが発生しました。これを回避する方法をWebで検索したところ、次のようなものが見つかりました。 このサイト .

を変更することができないので 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());
}

そこで質問です。このコードで大丈夫だと思いますか?

もちろん、あなたが何か改良したり、より良い方法を知っているならば、私は聞いています! :)

どのように解決するのですか?

の外側にロジックを移動させることができます。 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();
    }
}

こうすることで、呼び出し側が例外の StackTrace プロパティを検査するとき、それはまだ TaskThatFails 内のどこで投げられたかを記録します。