TaskContinuationOptions 是决定延续任务是否执行、何时执行、在哪执行及如何响应前序任务状态的核心枚举,其[Flags]特性支持位组合,但误用条件类(如OnlyOnRanToCompletion)与执行类(如ExecuteSynchronously)选项易致静默取消或运行时异常。

TaskContinuationOptions 是什么,为什么不能乱选
TaskContinuationOptions 不是“可有可无的配置项”,而是决定延续任务(continuation)**是否执行、何时执行、在哪执行、怎么响应前序任务状态**的核心开关。选错值会导致延续任务被静默取消、在错误线程上阻塞、或完全不触发——尤其在异常/取消场景下,表现和直觉严重不符。
它本质是一个 [Flags] 枚举,支持位运算组合(如 OnlyOnRanToCompletion | ExecuteSynchronously),但常见误用是把“条件类”和“执行类”选项混搭却不验证逻辑兼容性。
-
OnlyOnRanToCompletion:前序任务必须成功完成(IsFaulted == false && IsCanceled == false),否则延续直接变为Canceled状态,不会抛异常也不会执行委托 -
OnlyOnFaulted:仅当前序任务因异常结束(IsFaulted == true)才执行;此时antecedent.Exception可取到AggregateException,但注意需调用.Flatten()才能安全访问内层异常 -
OnlyOnCanceled:仅当IsCanceled == true时触发——但前提是前序任务**真被取消了**(即内部调用了cancellationToken.ThrowIfCancellationRequested()或检查了IsCancellationRequested);单纯调用cancellationTokenSource.Cancel()并不等于任务已取消 -
ExecuteSynchronously:延续任务**尝试**在前序任务结束的同一线程上同步执行(非强制,调度器可能忽略)。若前序任务在 UI 线程完成,这能避免跨线程访问控件异常;但若前序耗时长,会阻塞该线程——慎用于非 trivial 操作 -
LazyCancellation:已废弃(.NET Core 2.0+ 标记为 obsolete),实际行为不稳定,新项目应避免使用
常见组合陷阱与实操建议
多数问题出在“以为加了选项就保险”,结果延续根本没跑。关键要记住:所有 OnlyOnXxx 都是硬性守门员,不达标就拒之门外,且不报错。
- 想“无论成功失败都记录日志”?别写
OnlyOnRanToCompletion | OnlyOnFaulted——这是非法组合(位冲突),运行时报ArgumentOutOfRangeException。正确做法是用两个独立ContinueWith,或统一用无条件的默认重载(但需手动判断antecedent.Status) - 想“成功时发通知,失败时清理资源”?必须拆成两个延续:
task.ContinueWith(t => SendSuccessNotification(), TaskContinuationOptions.OnlyOnRanToCompletion); task.ContinueWith(t => CleanupResources(), TaskContinuationOptions.OnlyOnFaulted);
不能指望一个延续处理多状态 - 和
AttachedToParent搭配时,若父任务被WaitAll等待,而子延续因选项不满足被取消,父任务仍会认为“所有子任务已完成”,可能导致提前返回——这是隐蔽的竞态源
替代方案:为什么现在更推荐 await + try/catch
除非你在维护旧版 .NET Framework 4.x 代码,或必须精确控制调度线程(如 WinForms 同步上下文),否则 ContinueWith 已不是首选。现代 C# 中,await 天然处理任务状态分支,代码可读性和错误处理更直观:
享有盛誉的PHP高级教程,Zend Framework核心开发人员力作,深入设计模式、PHP标准库和JSON 。 今天,PHP已经是无可争议的Web开发主流语言。PHP 5以后,它的面向对象特性也足以与Java和C#相抗衡。然而,讲述PHP高级特性的资料一直缺乏,大大影响了PHP语言的深入应用。 本书填补了这一空白。它专门针对有一定经验的PHP程序员,详细讲解了对他们最为重要的主题
try
{
string result = await task;
Console.WriteLine($"Success: {result}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was canceled");
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
Console.WriteLine($"Faulted: {ex.Message}");
}ContinueWith 的回调式风格容易导致“回调地狱”,且 TaskContinuationOptions 的隐式取消行为让调试困难——比如延续没执行,你得逐层检查前序任务状态、选项组合、调度器是否为空,而不是直接看到异常堆栈。
最后提醒一个真实坑点
当你传入 TaskScheduler.FromCurrentSynchronizationContext() 给 ContinueWith,却在非 UI 线程(如后台线程池)调用它,FromCurrentSynchronizationContext() 返回的是 null,而 ContinueWith 会抛 ArgumentNullException——这个异常发生在延续注册时,而非任务完成时,极易被忽略。务必确保调用前 SynchronizationContext.Current != null,或改用 Task.Run(() => ..., scheduler) 显式包装。







