我有以下代码来处理我的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提出的建议,因为它是一个更清洁的解决方案。
正如我在其他答案中所说,你应该使用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。