使用 ContinueWith() 时如何获取原始异常?

Mat*_*son 5 c# exception .net-4.0 task

考虑以下代码:

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var tasks = new Task[1];

            tasks[0] = Task.Run(() => throwExceptionAfterOneSecond())
                .ContinueWith(task => {
                    Console.WriteLine("ContinueWith()"); }, TaskContinuationOptions.NotOnFaulted);

            try
            {
                Task.WaitAll(tasks);
            }

            catch (AggregateException ex)
            {
                Console.WriteLine("Exception received: " + ex.InnerExceptions.Single().Message);
            }
        }

        static void throwExceptionAfterOneSecond()
        {
            Thread.Sleep(1000);
            throw new InvalidOperationException("TEST");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

Exception received: A task was canceled.

我的问题很简单:我如何获得原件InvalidOperationException("TEST");而不是System.Threading.Tasks.TaskCanceledException?

请注意,如果您删除该.ContinueWith()部分,这将按我的预期工作,并且在这种情况下的输出为Exception received: TEST.

(还要注意,本例使用的是.Net 4.5,但原代码必须使用.Net 4.0)


解决方案

多亏了答案,这现在正在起作用。我选择了以下解决方案 - 我需要等待原始任务和延续任务:

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var tasks = new Task[2];

            tasks[0] = Task.Run(() => throwExceptionAfterOneSecond());

            tasks[1] = tasks[0].ContinueWith(task => {
                if (task.Status == TaskStatus.RanToCompletion)
                    Console.WriteLine("ContinueWith()"); });
            try
            {
                Task.WaitAll(tasks);
            }

            catch (AggregateException ex)
            {
                Console.WriteLine("Exception received: " + ex.InnerExceptions.Single().Message);
            }

            Console.WriteLine("Done.");
        }

        static void throwExceptionAfterOneSecond()
        {
            Thread.Sleep(1000);
            throw new InvalidOperationException("TEST");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

usr*_*usr 3

您需要存储对的引用,Task.Run(() => throwExceptionAfterOneSecond())以便以后可以检查它的Exception属性。这是唯一出错的任务。检查任何其他任务都不会提供该例外。

我也不会依赖,TaskContinuationOptions.NotOnFaulted因为这几乎迫使使用异常来控制流。等待非正常完成的任务而不抛出异常是很难的。

.ContinueWith(task => {
     if (task.Status == RanToCompletion) Console.WriteLine("ContinueWith()");
}
Run Code Online (Sandbox Code Playgroud)