web-dev-qa-db-ja.com

タスクの待機は、タスクの待機またはその例外プロパティへのアクセスによって確認されませんでした。その結果、観察されなかった例外は

これは何を意味し、どのように解決するのですか?

TPLタスクを使用しています。

全体のエラー

タスクの待機は、タスクの待機またはその例外プロパティへのアクセスによって確認されませんでした。その結果、ファイナライザースレッドによって、観察されなかった例外が再スローされました。

system.Threading.Tasks.TaskExceptionHolder.Finalize()で

mscorlib

93
MonsterMMORPG

タスクを作成し、task.Wait()を呼び出したり、Task<T>の結果を取得しようとしない場合、タスクがガベージコレクターによって収集されると、アプリケーションが破棄されます。ファイナライズ中。詳細については、MSDNのページ TPLの例外処理 を参照してください。

ここでの最良のオプションは、例外を「処理」することです。これは継続を介して行うことができます-タスクに継続を添付し、発生した例外を記録/飲み込む/などすることができます。これにより、タスクの例外をログに記録するクリーンな方法が提供され、単純な拡張メソッドとして記述できます。

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

上記を使用すると、次の方法で、タスクがアプリを破棄してログに記録するのを防ぐことができます。

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

または、 TaskScheduler.UnobservedTaskException にサブスクライブして、そこで処理することもできます。

151
Reed Copsey

承知しました; Taskがガベージコレクションに残された後にファイナライズされたが、タスク自体が失敗したことを意味します。次の2つの修正があります。

  • タスクを直接処理する(サブスクライブするにはContinueWith(...)を使用し、パラメーターのTaskで_.IsFaulted_および_.Exception_を確認します)
  • _TaskScheduler.UnobservedTaskException_イベントを処理し、監視対象としてマークします(エラーをログに記録した後、e.SetObserved()を呼び出します)
40
Marc Gravell