C# で非同期処理を行う際に使う async
/await
構文は非常に便利ですが、例外処理を正しく行わないと予期せぬ挙動やクラッシュの原因になります。この記事では、非同期メソッドにおけるエラーの捕捉方法や、try-catch
を用いた適切な書き方について解説します。
基本:非同期メソッドでの try-catch の使い方
非同期メソッドでも、基本的な例外処理は同期メソッドと同じように try-catch
を使用して行えます。
例:基本的な構文
public async Task GetDataAsync()
{
try
{
var result = await SomeHttpCallAsync();
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine($"エラーが発生しました: {ex.Message}");
}
}
非同期の処理(この場合は SomeHttpCallAsync
)が await
によって待機され、もし例外が発生した場合は catch
節で捕捉されます。
よくある注意点
1. await を忘れると catch で捕まえられない
以下のコードは間違いです:
try
{
SomeHttpCallAsync(); // await がない!
}
catch (Exception ex)
{
Console.WriteLine("捕捉できない");
}
この場合、非同期メソッドはバックグラウンドで実行されており、例外が発生しても try-catch
では捕捉できません。必ず await
を付けてください。
2. 呼び出し元のメソッドでのエラー処理も重要
非同期メソッドを呼び出す側で例外を処理したい場合も、同様に await
+ try-catch
を使います。
public async Task MainAsync()
{
try
{
await GetDataAsync();
}
catch (Exception ex)
{
Console.WriteLine($"呼び出し元でエラー処理: {ex.Message}");
}
}
3. 複数の await を使う場合
複数の await があると、それぞれ個別に try-catch を入れた方が原因の特定がしやすくなります。
try
{
var data = await LoadDataAsync();
}
catch (Exception ex)
{
Console.WriteLine("LoadDataAsync のエラー: " + ex.Message);
}
try
{
var result = await ProcessDataAsync();
}
catch (Exception ex)
{
Console.WriteLine("ProcessDataAsync のエラー: " + ex.Message);
}
特殊ケース:非同期イベントハンドラ
非同期のイベントハンドラでは、例外が UI スレッドに伝わらないことがあります。UI アプリケーション(WPF や WinForms)では、非同期イベント内でも try-catch
を明示的に書く必要があります。
private async void Button_Click(object sender, EventArgs e)
{
try
{
await DoSomethingAsync();
}
catch (Exception ex)
{
MessageBox.Show("エラー: " + ex.Message);
}
}
Task の例外と Observe
Task
を返すだけのメソッドで await
せずに実行すると、例外が未処理になる可能性があります。
たとえば、Task.Run(() => throw new Exception())
のようなケースでは注意が必要です。
対策:
await
してキャッチする- または
ContinueWith
を使って例外を監視する
まとめ
async
メソッド内でもtry-catch
は有効await
を忘れると例外がキャッチできない- 呼び出し元でも
try-catch
を使って例外を伝播させる - 非同期イベントや UI アプリでは例外が伝わりにくいため明示的に処理を行う
非同期処理における例外処理は、アプリの安定性に直結します。正しい構文と理解で、安全な非同期プログラムを構築しましょう。