###介绍
在对我的代码困惑了一段时间后,我发现异常不一定会通过以下方式传播ContinueWith
:
int zeroOrOne = 1;
Task.Factory.StartNew(() => 3 / zeroOrOne)
.ContinueWith(t => t.Result * 2)
.ContinueWith(t => Console.WriteLine(t.Result))
.ContinueWith(_ => SetBusy(false))
.LogExceptions();
在此示例中,SetBusy
行“重置”异常链,因此看不到除以零异常,随后在我的脸上炸开了“未观察到任务的异常......”
所以......我给自己写了一个小扩展方法(有很多不同的重载,但基本上都是这样做的):
public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
return task.ContinueWith(t =>
{
if(t.IsFaulted) throw t.Exception;
continuation(t);
});
}
再四处搜索,我发现了这篇博文,他提出了一个类似的解决方案,但使用了 TaskCompletionSource,它(意译)看起来像这样:
public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
var tcs = new TaskCompletionSource<object>();
task.ContinueWith(t =>
{
if(t.IsFaulted) tcs.TrySetException(t.Exception);
continuation(t);
tcs.TrySetResult(default(object));
});
return tcs.Task;
}
###Question 这两个版本是否严格等效?throw t.Exception
还是和之间有细微的差别tcs.TrySetException(t.Exception)
?
此外,整个互联网上显然只有另一个人这样做的事实是否表明我错过了这样做的惯用方式?