TPL и обработка исключений - PullRequest
8 голосов
/ 27 марта 2012

Все, есть много вопросов по вышеуказанной теме, но я считаю, что это достаточно отличается, чтобы оправдать новый вопрос. У меня есть следующее Task и продолжение для решения различных задач Status; TaskStatus.RanToCompletion, TaskStatus.Canceled и, конечно, AggregateException через TaskStatus.Faulted. Код выглядит как

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 будет брошено изнутри продолжения - что тогда?

Я не хочу Wait на моем asyncTask, ни на продолжении, поскольку это заблокирует возврат в поток пользовательского интерфейса. Чтобы поймать любые исключения, выбрасываемые из продолжения, не значит, что я обязательно должен сделать что-то подобное

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

будет ли это вообще работать? Какова лучшая практика здесь?

Как всегда, спасибо за ваше время.

Ответы [ 2 ]

12 голосов
/ 27 марта 2012

Вы можете использовать традиционные try / catch внутри ваших делегатов, следя за AggregateException, или вы можете связать определенные продолжения, которые будут выполняться только в том случае, если антецедент отказал, используя опцию 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 голосов
/ 27 марта 2012

Msdn имеет довольно хорошо написанное «Как» по этому вопросу: здесь

Вы заметите, что они просто используют try/catch(AggregateException) блок, а затем отфильтруйте исключение, которое они знают, какобработать в ae.Handle(lambda) и сделать остановку приложения, если остались какие-то не обрабатываемые.

...