C# – 失敗したタスクの例外を処理する

Task が例外をスローして実行を停止すると、それは障害が発生しています。問題は、失敗したタスクからスローされた例外をどのように取得するかです。

これは、タスクを待っているかどうかによって異なります。

この記事では、タスクを待機している場合と待機していない場合の 2 つのシナリオで、失敗したタスクの例外を処理する方法を示します。

待機していないタスクの例外の処理

バックグラウンド タスクを開始していて、それを待っていないとしましょう。このタスクは、ファイル システムの監視など、あらゆることを行っている可能性があります。障害が発生した場合は、対応できるようにする必要があります。この例では、根本原因の例外をログに記録しているだけです。

タスクの例外を処理するには、.ContinueWith() を呼び出して継続を追加し、TaskContinuationOptions.OnlyOnFaulted オプションを指定します。これは、タスクに例外があった場合にのみ継続が実行されることを意味します。

継続タスクの例外は AggregateException です。根本原因の例外を取得するには、GetBaseException() を使用します。

Task.Run(BackgroundTask).ContinueWith(t =>
{
	var ex = t.Exception?.GetBaseException();
	if (ex != null)
	{
		Logger.Error($"Task faulted and stopped running. ErrorType={ex.GetType()} ErrorMessage={ex.Message}");
	}
},
TaskContinuationOptions.OnlyOnFaulted);
Code language: C# (cs)

バックグラウンド タスクで意図的に NotFiniteNumberException をスローしています。したがって、このコードを実行すると、次のようになります:

Task faulted and stopped running. ErrorType=System.NotFiniteNumberException ErrorMessage=Number encountered was not a finite quantity.Code language: plaintext (plaintext)

待機中のタスクの例外の処理

タスクを待機できる場合は、はるかに簡単です。 try/catch ブロック内でタスクを待機できます。タスクが失敗すると、フレームワークは AggregateException をラップ解除し、スローされた基本例外を処理できるようにします。

try
{
	await BackgroundTaskAsync();
}
catch (Exception ex)
{
	Logger.Error($"Task faulted and stopped running. ErrorType={ex.GetType()} ErrorMessage={ex.Message}");
}
Code language: C# (cs)

このコードを実行すると、次のようになります:

Task faulted and stopped running. ErrorType=System.NotFiniteNumberException ErrorMessage=Number encountered was not a finite quantity.Code language: plaintext (plaintext)