TaskContinuationOptions OnlyOnCancelled 捕获未处理的错误
TaskContinuationOptions OnlyOnCancelled catches unhandled errors
我有以下代码来处理我的 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 调用的方法中调用的。我解释说在这个 post
更新
我使用的是 Task.Run,而不是上面的代码。我正在用异步装饰传入 Task.Run 的 lambda,以提供 "Async all the way",正如 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) {}
});
这感觉是一个更好的解决方案,因为我可以用 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
returns一个任务代表延续,而不是前件。为了简化您问题中的代码:
GetDataAsync(id)
.ContinueWith(A(), TaskContinuationOptions.OnlyOnRanToCompletion);
.ContinueWith(B(), TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith(C(), TaskContinuationOptions.OnlyOnCanceled);
如果 GetDataAsync(id)
运行完成,将调用 A()
。 B()
将在 A()
故障时被调用(注意:如果 GetDataAsync(id)
故障则不会)。如果 B()
被取消,C()
将被调用(注意:如果 GetDataAsync(id)
被取消则不会)。
您对 ContinueWith
的使用还有一些其他问题:它缺少一些标志(例如 DenyChildAttach
),并且它使用的是当前的 TaskScheduler
,这可能会导致令人惊讶的行为。 ContinueWith
is an advanced, low-level method; use await
instead.
我有以下代码来处理我的 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 调用的方法中调用的。我解释说在这个 post
更新
我使用的是 Task.Run,而不是上面的代码。我正在用异步装饰传入 Task.Run 的 lambda,以提供 "Async all the way",正如 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) {}
});
这感觉是一个更好的解决方案,因为我可以用 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
returns一个任务代表延续,而不是前件。为了简化您问题中的代码:
GetDataAsync(id)
.ContinueWith(A(), TaskContinuationOptions.OnlyOnRanToCompletion);
.ContinueWith(B(), TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith(C(), TaskContinuationOptions.OnlyOnCanceled);
如果 GetDataAsync(id)
运行完成,将调用 A()
。 B()
将在 A()
故障时被调用(注意:如果 GetDataAsync(id)
故障则不会)。如果 B()
被取消,C()
将被调用(注意:如果 GetDataAsync(id)
被取消则不会)。
您对 ContinueWith
的使用还有一些其他问题:它缺少一些标志(例如 DenyChildAttach
),并且它使用的是当前的 TaskScheduler
,这可能会导致令人惊讶的行为。 ContinueWith
is an advanced, low-level method; use await
instead.