タスクの待機は、タスクで待機することも、Exceptionプロパティにアクセスすることもできませんでした。その結果、観察されなかった例外は


100

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

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

エラー全体

タスクの待機は、タスクで待機することも、Exceptionプロパティにアクセスすることもできませんでした。その結果、監視されていない例外がファイナライザスレッドによって再スローされました。

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

mscorlib

回答:


158

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

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

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をサブスクライブしてそこで処理することもできます。


17
エンターテインメントを追加するにOffは、任意の4文字の単語として名前が付けられたクラスに静的スタブメソッドを用意し、これをキャッチオール継続に使用します。この特定の例外によるうんざりした欲求不満のいくつかを解消するのに役立ちます。
アーロンノート、2011年

1
@MonsterMMORPGはい-基本的に、どこかで例外をキャッチまたは処理する必要があります。どこかでそれを処理する限り、あなたの中心的な問題はなくなります。
リードコプシー、2011年

1
ContinueWithの呼び出しが行われる前に、タスクが例外をスローする可能性はありませんか?
Tim Sylvester、

1
@TimSylvester継続がアタッチされる「前」に発生した場合でも、フレームワークは継続を通じてそれをマッピングします
Reed Copsey

32
重要な注意:これはにのみ必要です.Net 4.0。例外処理は、アプリケーションを破棄しないようにデフォルトで変更されまし.net 4.5た。詳細については、.NET 4.5のタスク例外処理を参照してください
i3arnon

43

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

  • タスクは、直接(使用が失敗扱うContinueWith(...)購読すると、チェック.IsFaultedして.ExceptionTaskのパラメータで)
  • TaskScheduler.UnobservedTaskExceptionイベントを処理し、監視済みとしてマークします(e.SetObserved()エラーを記録した後に呼び出します)

4
+1-1つの追加で-継続がを確認するIsFaultedだけの場合は、OnlyOnFaulted継続オプションを使用して手動での確認を回避できます...
Reed Copsey

実際、これは、tplタスク内でpublic static関数を呼び出したときに発生しました。try catchを使用すると、この問題が解決しますか?本当に別のタスクを作成してそれを待つ必要がありますか?感謝
MonsterMMORPG

4
これを言及するための1 SetObservedUnobservedTaskExceptionEventArgs呼び出す必要があります。
James Webster

-17

これを試してください:

public static void ThrowFirstExceptionIfHappens(this Task task)
{
    task.ContinueWith(t =>
    {
        var aggException = t.Exception.Flatten();
        foreach (var exception in aggException.InnerExceptions)
        {
            throw exception; // throw only first, search for solution
        }
    },
    TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}

public static Task CreateHandledTask(Action action) 
{
    Task tsk = Task.Factory.StartNew(action);
    tsk.ThrowFirstExceptionIfHappens();
    return tsk;
}

5
それは1つです ??? どういう意味ですか?あなたの答えがこれまでの答えに貢献していることを説明していただけますか?
Gert Arnold

続行して新しいタスクを作成したところ、失敗して同じ状況になります。
Robert Taylor

このソリューションは少し複雑なようです。機能を意図せずに非表示にしても、利益が得られないと思います。
Velocitas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.