.NET Core中SynchronizationContext是否不再随ExecutionContext流动?
你的观察完全正确——这个被Stephen Toub称作设计失误的问题,确实在.NET Core中被修复了,SynchronizationContext不再作为ExecutionContext承载的流动上下文之一。
先回顾.NET Framework的历史问题
在.NET Framework中,SynchronizationContext确实被打包在ExecutionContext里一起流动,这是早期API设计的疏漏。正如Stephen Toub在博客中提到的:
SynchronizationContext属于ExecutionContext承载的流动上下文(如SecurityContext、HostExecutionContext等)之一,他认为这是API设计失误,但因兼容性长期未修改。.NET Framework中多数mscorlib内的异步操作不会流动该上下文,其他操作则会。
当时内部方法还存在preserveSyncCtx参数,用来控制是否在ExecutionContext中包含SynchronizationContext,以此作为兼容性妥协的手段。
.NET Core的修复与行为变化
到了.NET Core时代,团队彻底重构了这部分逻辑:
- 源码中移除了
preserveSyncCtx相关参数,明确将SynchronizationContext的流动与ExecutionContext分离开来。 - ExecutionContext现在仅承载与安全、宿主环境相关的上下文(比如SecurityContext、HostExecutionContext),不再包含SynchronizationContext。
你的测试结果正好验证了这一点:
- 在.NET Framework中,捕获的ExecutionContext包含了设置的
TestSynchronizationContext,所以ExecutionContext.Run时能恢复出该上下文,断言通过。 - 在.NET Core 3.1中,捕获的ExecutionContext里根本没有保存SynchronizationContext,所以
syncCtxBox.Value为默认上下文(或null),断言失败。
关于文档滞后的说明
微软官方文档确实存在更新不及时的情况,部分内容仍沿用了.NET Framework时期的描述,这也是导致你困惑的原因。实际行为以代码运行结果和.NET Core源码为准。
补充:现在SynchronizationContext怎么流动?
在.NET Core及后续版本(包括.NET 5+)中,SynchronizationContext的流动是由异步操作的ConfigureAwait机制独立处理的:
- 当你使用
await task.ConfigureAwait(true)时,会捕获当前的SynchronizationContext,并在任务完成后恢复到该上下文执行后续代码。 - 如果使用
ConfigureAwait(false),则不会捕获和恢复SynchronizationContext,后续代码会在线程池线程上执行。
这部分逻辑完全独立于ExecutionContext的流动机制。
内容的提问来源于stack exchange,提问作者Erlend Graff

