3

如何将任务中引发的异常标记为已处理。问题是当我调用一个任务的方法时,即使我很久以前已经处理过了Wait(),它也会抛出一个。以下代码片段显示了我要解决的问题。在我的原始代码中,我处理代码的一部分,并在代码的另一部分中调用该方法。但问题是一样的。AggregateExceptionAggregateExceptionAggregateExceptionWait()

static void Main(string[] args)
{
    Task task = null;

    try
    {
        task = new Task(() =>
        {
            Console.WriteLine("Task started");
            Thread.Sleep(1000);
            throw new InvalidOperationException("my test exception");
        });

        task.ContinueWith(t => 
        {
            Console.WriteLine("Task faulted");
            AggregateException ae = t.Exception;
            ae.Flatten().Handle(ex =>
            {
                if (typeof(InvalidOperationException) == ex.GetType())
                {
                    Console.WriteLine("InvalidOperationException handled --> " + ex.Message);
                    return true;
                }

                return false;
            });
        }, TaskContinuationOptions.OnlyOnFaulted);

        task.Start();
        Thread.Sleep(2000);
        task.Wait();
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("AggregateException thrown again!!! Why???");
        ae.Flatten().Handle(ex =>
            {
                Console.WriteLine(ex.Message);
                return true;
            });              
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    Console.WriteLine("Finished");
    Console.Read();
}

上面的代码产生以下输出:

  • 任务开始
  • 任务出错
  • 处理了 InvalidOperationException --> 我的测试异常
  • 再次抛出 AggregateException !!!为什么???
  • 我的测试异常
  • 完成的
4

1 回答 1

2

当一个错误的任务被Wait编辑时,异常被重新抛出。如果只是偶尔抛出异常,那将是不可靠的设计。

但是,如果您要添加一个处理异常的延续并且您不希望它再次抛出,那么就不要再执行Wait该任务了。Wait继续任务(您当前未使用)。它只会在原始任务完成后完成,如果您需要结果,只需继续返回即可。这样异常只会被处理一次:

Task continuation = task.ContinueWith(t => 
{
    Console.WriteLine("Task faulted");
    AggregateException ae = t.Exception;
    ae.Flatten().Handle(ex =>
    {
        if (typeof(InvalidOperationException) == ex.GetType())
        {
            Console.WriteLine("InvalidOperationException handled --> " + ex.Message);
            return true;
        }

        return false;
    });
}, TaskContinuationOptions.OnlyOnFaulted);

task.Start();
Thread.Sleep(2000);
continuation.Wait();

注意:TaskCanceledException当原始任务因为继续被取消(由于 )而没有引发异常时,这将引发 a TaskContinuationOptions.OnlyOnFaulted。为避免这种情况,只需删除标志并检查t.IsFaulted.

于 2014-11-27T23:21:40.080 回答