TaskContinuationOptions OnlyOnCancelled ловит необработанные ошибки - PullRequest
0 голосов
/ 04 марта 2019

У меня есть следующий код для обработки моего TaskContinuations.Я немного растерялся, потому что у меня есть блок ниже OnlyOnFaulted, который, как я ожидаю, будет введен, если задача сгенерирует необработанное исключение.

Однако необработанное исключение, обработанное исключение, которое перебрасывается с помощью throw, или отмена попадет вблок OnlyOnCanceled.

GetDataAsync(id).ContinueWith((antecedant) =>
{
    // do something when async method completed
    }, TaskContinuationOptions.OnlyOnRanToCompletion)
    .ContinueWith((antecedant) =>
    {
        var error = antecedant.Exception.Flatten(); //so when is this called if everything is cought by OnCancelled below?
    }, TaskContinuationOptions.OnlyOnFaulted)
    .ContinueWith((antecedant) =>
    {
        // this is fired if method throws an exception or if CancellationToken cancelled it or if unhandled exception cought
        var error = "Task has been cancelled";
    }, TaskContinuationOptions.OnlyOnCanceled);

Я ожидаю, что повторно сгенерированные ошибки и отмены попадут в блок OnlyOnCanceled, тогда как необработанное исключение попадет в блок OnlyOnFaulted

Обратите внимание, что я не могу просто await GetDataAsync, потому что это вызывается в методе, вызываемом из c-tor View.Я объяснил, что в этом посте NetworkStream ReadAsync и WriteAsync бесконечно зависают при использовании CancellationTokenSource - тупик, вызванный Task.Result (или Task.Wait)

UPDATE

Вместо того чтобы использовать код выше, я использую Task.Run, как показано ниже.Я украшаю лямбду, переданную в Task.Run, с помощью async, чтобы обеспечить "Async полностью", как рекомендовано Джоном Голдбергером в https://blog.xamarin.com/getting-started-with-async-await/

Task.Run(async() =>  
{
    try
    {
        IList<MyModel> models = await GetDataAsync(id);
        foreach (var model in models)
        {
            MyModelsObservableCollection.Add(model);
        }
    } catch (OperationCancelledException oce) {}
    } catch (Exception ex) {}

});

Это было лучшим решением, так как я могу обернуть код внутриTask.Run с блоком try ... catch, и обработка исключений ведет себя так, как я и ожидал.

Я определенно планирую попробовать предложение, предложенное Стивеном Клири на https://msdn.microsoft.com/en-us/magazine/dn605875.aspx, так какшов, чтобы быть более чистым решением.

1 Ответ

0 голосов
/ 06 марта 2019

Как я уже говорил в моем другом ответе, вы должны использовать await, и, поскольку это конструктор для ViewModel, вы должны синхронно инициализировать в состояние "Загрузка ..." и асинхронно обновить , чтобы ViewModel перешел в состояние «Отображение данных» .

Чтобы ответить на этот вопрос напрямую, проблема в том, что ContinueWith возвращает задачу , представляющую продолжение , а неантецедент.Чтобы упростить код в вашем вопросе:

GetDataAsync(id)
    .ContinueWith(A(), TaskContinuationOptions.OnlyOnRanToCompletion);
    .ContinueWith(B(), TaskContinuationOptions.OnlyOnFaulted)
    .ContinueWith(C(), TaskContinuationOptions.OnlyOnCanceled);

A() будет вызван, если GetDataAsync(id) завершится.B() будет вызван, если A() неисправен (примечание: нет, если GetDataAsync(id) неисправен).C() будет вызван, если B() отменен (примечание: нет, если GetDataAsync(id) отменен).

Есть несколько других проблем с использованием ContinueWith: отсутствуют некоторые флаги (например, DenyChildAttach), и он использует текущий TaskScheduler, что может вызвать неожиданное поведение.ContinueWith - продвинутый метод низкого уровня;используйте await вместо .

...