等待任务或访问其Exception属性都未观察到Task的异常。结果,未观察到的异常是


100

这是什么意思,如何解决?

我正在使用TPL任务。

整个错误

等待任务或访问其Exception属性都未观察到Task的异常。结果,未观察到的异常被终结器线程抛出。

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

mscorlib

Answers:


158

如果创建一个Task,并且您从未调用task.Wait()或尝试检索a的结果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在您选择的名为四个字母的单词的类中使用静态存根方法,并将其用于包罗万象的延续。有助于消除由于这种特殊异常而导致的一些沮丧情绪。
— 亚伦诺特,2011年

1
@MonsterMMORPG是-您基本上必须在某个地方捕获或处理异常。只要您在某个地方处理它,您的核心问题就会消失。
— Reed Copsey

1
在对ContinueWith进行调用之前,任务是否有可能引发异常?
— 蒂姆·西尔维斯特

1
@TimSylvester该框架仍将通过延续映射它,即使它发生在“延续”附加之前
— Reed Copsey 2012年

32
重要说明:仅对才需要.Net 4.0。默认情况下,异常处理已更改.net 4.5为不关闭应用程序。在.NET 4.5
— i3arnon 2014年

43

当然; 这意味着将Task其留给垃圾收集后完成,但是任务本身失败了。有两个修复程序:

  • 处理任务失败直接(使用ContinueWith(...)订阅,检查.IsFaulted和.Exception对Task在参数)
  • 处理TaskScheduler.UnobservedTaskException事件并标记为已观察到(e.SetObserved()记录错误后调用)

4
+1-另加一项-如果您的继续操作只检查了IsFaulted,则可以使用OnlyOnFaulted继续选项,而无需手动检查...
— Reed Copsey

实际上,这发生在我在tpl任务中调用了一个公共静态函数的地方。使用try catch可以解决此问题吗?我真的需要创建另一个任务并等待吗?谢谢
— MonsterMMORPG

4
+1需要提及SetObservedon UnobservedTaskExceptionEventArgs。
— 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
它的一个 ??? 你什么意思?您能解释一下到目前为止您的答案对答案有什么贡献吗?
— Gert Arnold

您刚刚通过继续创建了一个新任务,该任务将失败并陷入相同的情况。
— 罗伯·泰勒

这个解决方案似乎有点令人费解。我认为您会无意间隐藏功能而没有任何收获。
— Velocitas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.