プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2019/06/11

[C#] 非同期処理中の例外キャッチについて

update2019/06/12 event_note2019/06/11 9:39

非同期処理中に発生した例外をキャッチする際にちょっとはまったのでメモします。

非同期処理中に発生した例外をキャッチしたい場合、その非同期処理を await している場合と、Wait() で同期処理のように扱った場合とで発生する例外が異なり、ちょっとはまりました。

Wait していた場合

例えば以下のように Wait() していた場合に InvalidOperationException が発生したとします。

public static void Main()
{
    try
    {
        Task.Run(() =>
        {
            throw new InvalidOperationException();
        }).Wait();
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine("InvalidOperationException!");
        Console.WriteLine(ex.GetType());
        Console.WriteLine(ex.InnerException?.GetType());
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception!");
        Console.WriteLine(ex.GetType());
        Console.WriteLine(ex.InnerException?.GetType());
    }

    Console.ReadKey();
}

出力結果

Exception!
System.AggregateException
System.InvalidOperationException

結果からわかる通り、 InvalidOperationException ではキャッチできません。

例外の型は AggregateException になっており、InnerExceptionInvalidOperationException が格納されていました。

await していた場合

非同期処理を await していた場合は InvalidOperationException でキャッチできます。

public static async Task Main()
{
    try
    {
        await Task.Run(() =>
        {
            throw new InvalidOperationException();
        });
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine("InvalidOperationException!");
        Console.WriteLine(ex.GetType());
        Console.WriteLine(ex.InnerException?.GetType());
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception!");
        Console.WriteLine(ex.GetType());
        Console.WriteLine(ex.InnerException?.GetType());
    }
}

出力結果

InvalidOperationException!
System.InvalidOperationException