【发布时间】:2019-03-07 05:38:59
【问题描述】:
我有以下代码来处理我的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,而不是使用上面的代码。按照 Jon Goldberger 在https://blog.xamarin.com/getting-started-with-async-await/
的建议,我正在用 async 装饰传递给 Task.Run 的 lambda,以提供“一路异步”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来添加延续,而不是ContinueWith,基本上在所有情况下,正是因为编写这样的代码要正确地编写代码要困难得多。省心。 -
这不是不使用
await的理由。鉴于您对问题的描述,您应该绝对使用await添加这些延续。如果您确实想触发并忘记此操作(这不太可能,那么在构造函数中不太可能有一些事情要做,您不想知道它何时完成或从构造函数返回一个对象时它没有'没有完成一些用于构造它的操作(如果它不是用于构造它的操作,那么你不应该从构造函数中调用它))然后你可以触发并忘记一个异步方法。
标签: c# async-await task continuations