我有以下代码来处理我的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)
更新
不是使用上面的代码,而是使用Task.Run,如下所示。我正在装饰传递给Task.Run的lambda,并按照Jon Goldberger在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.Task中,使用try ... catch块运行,并且异常处理的行为符合我的预期。
我绝对打算尝试在https://msdn.microsoft.com/en-us/magazine/dn605875.aspx上提供Stephen Cleary提出的建议,因为它似乎是一种更清洁的解决方案。
答案 0 :(得分: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。