Пометить исключение задачи как обработанное

Как я могу отметить исключение, брошенное в задачу, как обработанную. Проблема в том, когда я звоню Wait() метод задачи, он бросит AggregateException даже когда я уже занимался AggregateException давным давно. Следующий фрагмент кода показывает проблему, которую я хочу решить. Я мой оригинальный код, я обрабатываю AggregateException в одной части моего кода, и я называю Wait() метод в другой части моего кода. Но проблема та же.

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 выдается снова!!! Зачем???
  • мое тестовое исключение
  • Законченный

1 ответ

Решение

Когда ошибочная задача 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 когда исходное задание не выдает исключение, потому что продолжение отменено (из-за TaskContinuationOptions.OnlyOnFaulted). Чтобы избежать этого, просто удалите флаг и проверьте, t.IsFaulted,

Другие вопросы по тегам