TPL和异常处理

8

大家好,虽然与上述主题有许多问题,但我认为这个问题足够不同,需要提出一个新问题。我有以下的任务(Task)和一个用来处理多种任务状态(Status)的延续; TaskStatus.RanToCompletion, TaskStatus.Canceled和当然是通过TaskStatus.FaultedAggregateException。代码如下:

Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
    asyncMethod(uiScheduler, token, someBoolean), token);

asyncTask.ContinueWith(task =>
{
    // Check task status.
    switch (task.Status)
    {
        // Handle any exceptions to prevent UnobservedTaskException.             
        case TaskStatus.RanToCompletion:
            if (asyncTask.Result)
            {
                // Do stuff...
            }
            break;
        case TaskStatus.Faulted:
            if (task.Exception != null)
                mainForm.progressRightLabelText = task.Exception.InnerException.Message;
            else
                mainForm.progressRightLabelText = "Operation failed!";
        default:
            break;
    }
}

这一切都很好,但我担心自己是否做得正确,因为在继续执行时可能会抛出AggregateException,那怎么办呢?

我不想等待我的asyncTask和continuation,因为这会阻塞返回到UI线程。要捕获从continuation中抛出的任何异常肯定不能意味着我必须像这样做吧。

Task parentTask = Task.Factory.startNew(() => 
    {
        Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
            asyncMethod(uiScheduler, token, someBoolean), token);

        Task continueTask = asyncTask.ContinueWith(task =>
            {
                // My continuation stuff...   
            }

        try
        {
            continueTask.Wait();
        }
        catch(AggregateException aggEx)
        { 
            // Some handling here...
        }
    });

这会有效吗?这里的最佳实践是什么?
像往常一样,感谢您的时间。

我曾经见过一些任务在“完成”时实际上抛出了AggregateException异常。这种错误处理方式行不通。为什么不直接使用try/catch呢? - Louis Kottmann
你的意思是在后台线程上调用的方法中,还是在实际的继续委托方法中? - MoonKnight
2个回答

12

您可以在监视AggregateException的委托中使用传统的try/catch语句,或者可以通过使用TaskContinuationOptions.OnlyOnFaulted选项链接具体的延续,这些延续仅在前置任务失败时才运行。后一种方法允许定义非常清晰的任务工作流程。例如:

Task myRootTask = ....;

myRootTask.ContinueWith(rootAntecdent =>
{
    // this will only be executed if the antecedent completed successfully, no need to check for faults
},
TaskContinuationOptions.OnlyOnRanToCompletion);

myRootTask.ContinueWith(rootAntecedent =>
{
    // this will only be executed if the antecedent faulted, observe exception and handle accordingly
},
TaskContinuationOptions.OnlyOnFaulted);

2

Msdn有一篇关于这个主题的相当好的"How to"文章:在这里

你会注意到他们只是使用了一个try/catch(AggregateException)块,然后在ae.Handle(lambda)中过滤他们知道如何处理的异常,如果还有一些无法处理的异常,则使应用程序停止。


我知道像你提供链接中的例子,并且对于这种异常处理方式没有问题。我的问题是如何处理从continuations抛出的异常,而不需要用try catch包含整个continuation委托,但也许这可能是唯一的方法。我想了解现实世界代码的最佳实践,而不是Microsoft玩具代码的最佳实践。干杯。 - MoonKnight
OP想知道如何在不使用Wait的情况下完成此操作。这些示例都会等待任务完成。请尝试使用此链接[http://msdn.microsoft.com/en-us/library/dd997415.aspx]。 - Jordan Morris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接