TaskContinuationOptions OnlyOnCancelled捕获未处理的错误

问题描述 投票:0回答:1

我有以下代码来处理我的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,因为这是在View的c-tor调用的方法中调用的。我在这篇文章中解释了NetworkStream ReadAsync and WriteAsync hang infinitelly when using CancellationTokenSource - Deadlock Caused by Task.Result (or Task.Wait)

UPDATE

而是使用上面的代码,我正在使用如下的Task.Run。我正在使用async来装饰传递给Task.Run的lambda以提供Jon Goldberger在https://blog.xamarin.com/getting-started-with-async-await/推荐的“Async all as way”

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

});

这感觉是一个更好的解决方案,因为我可以使用try ... catch块将代码包装在Task.Run中,并且异常处理的行为正如我所期望的那样。

我肯定打算尝试一下Stephen Cleary在https://msdn.microsoft.com/en-us/magazine/dn605875.aspx提出的建议,因为它是一个更清洁的解决方案。

c# async-await task continuations
1个回答
0
投票

正如我在其他答案中所说,你应该使用await,因为这是ViewModel的构造函数,你应该使用synchronously initialize to a "Loading..." state and asynchronously update that ViewModel to a "Display Data" state

要直接回答这个问题,问题是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 is an advanced, low-level method; use await instead

© www.soinside.com 2019 - 2024. All rights reserved.