通过等待任务或访问其Exception属性,未观察到任务的异常。结果,未观察到的例外是

时间:2011-10-24 23:16:57

标签: c# wpf exception task task-parallel-library

这是什么意思以及如何解决它?

我正在使用TPL任务。

整个错误

  

通过等待任务或访问其Exception属性,未观察到任务的异常。结果,终结器线程重新抛出了未观察到的异常。

     

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

     

mscorlib程序

3 个答案:

答案 0 :(得分:148)

如果您创建了一个任务,并且您没有调用task.Wait()或尝试检索Task<T>的结果,那么当垃圾收集器收集任务时,它将会拆除您的任务最终确定期间的申请。有关详细信息,请参阅Exception Handling in the 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并在那里处理。

答案 1 :(得分:38)

不确定;这意味着Task在被留给垃圾收集后最终确定,但任务本身失败了。有两个修复:

  • 直接处理任务失败(使用ContinueWith(...)订阅,并在参数中的.IsFaulted上查看.ExceptionTask
  • 处理TaskScheduler.UnobservedTaskException事件,并将其标记为已观察(在记录错误后调用e.SetObserved()

答案 2 :(得分:-15)

试试这个:

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;
}