system.text.json源生成器启用失败的常见原因包括未启用implicitusings和nullable、未引用正确版本包、未正确定义partial jsonserializercontext类及[jsonserializable]特性,且必须使用生成的上下文实例调用serialize/deserialize方法。

System.Text.Json源生成器启用失败的常见原因
源生成器在 .NET 6+ 中默认不启用,即使项目 SDK 是 Microsoft.NET.Sdk,也必须显式开启源生成支持。最常被忽略的是未在 .csproj 中设置 ImplicitUsings 和 Nullable,或未引用正确的包版本。
-
System.Text.Json源生成依赖System.Text.Json.SourceGeneration包(.NET 7+ 内置,但需确认 SDK 版本;.NET 6 需手动安装System.Text.Json6.0.3+) - 项目必须启用
<implicitusings>enable</implicitusings>,否则JsonSerializerContext相关类型无法解析 - 若使用
partial类型定义上下文,类名必须以JsonSerializerContext结尾,且标记[JsonSerializable]—— 否则生成器不触发 - 生成器输出在
obj/Debug/netX.X/下的GeneratedSources/文件夹中,若该目录为空,说明生成未执行,可检查dotnet build -v:d日志中是否有SourceGenerator相关警告
如何正确定义 JsonSourceGenerationContext
源生成器不是自动扫描所有类型,而是基于你声明的 JsonSerializerContext 子类,显式列出需要序列化的类型。这个类必须是 partial,且每个 [JsonSerializable] 属性对应一个根类型(支持嵌套、泛型、接口,但不支持 object 或未标注的运行时类型)。
[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(List<Person>))]
[JsonSerializable(typeof(Dictionary<string, Order>))]
internal partial class AppJsonContext : JsonSerializerContext
{
}
-
Person和Order类本身不需要额外标记,但字段/属性访问必须为public,或通过[JsonInclude]开放private成员 - 若类型含
DateTimeOffset、Guid等,无需额外配置,默认已优化;但自定义转换器(如JsonConverter<t></t>)仍需在上下文中注册:[JsonSerializable(typeof(Person), TypeInfoPropertyName = "PersonInfo")]+ 手动实现PersonInfo属性 - 不支持动态类型(如
ExpandoObject)、dynamic、未闭合泛型(List)—— 这些会跳过生成,回退到反射路径
序列化/反序列化时如何正确使用生成的上下文
启用源生成后,不能继续用静态 JsonSerializer.Serialize<t>(value)</t>,那仍走反射路径。必须传入生成的 AppJsonContext.Default 实例,并使用其 Serialize/Deserialize 方法,才能命中编译期生成的代码路径。
var context = AppJsonContext.Default; string json = context.Serialize(person); // ✅ 调用生成的代码 Person p = context.Deserialize<Person>(json); // ✅ // ❌ 以下仍走反射,完全绕过源生成 string json2 = JsonSerializer.Serialize(person); Person p2 = JsonSerializer.Deserialize<Person>(json2);
-
AppJsonContext.Default是线程安全的单例,可全局复用,无需缓存或池化 - 若需不同选项(如
PropertyNamingPolicy),必须定义多个partial上下文类,每个带独立[JsonSourceGenerationOptions]特性;无法在运行时切换同一上下文的选项 - 生成代码对
null值处理与反射路径一致,但字段级JsonIgnore必须在类型定义时存在,运行时通过JsonSerializerOptions添加的忽略规则无效
性能差异在哪?什么场景下值得上源生成
源生成主要消除反射调用和运行时类型检查开销,在高频、小对象、固定结构的 JSON 场景下收益明显(如微服务间 DTO 通信、API 响应序列化)。但它的优势不是“绝对更快”,而是“更稳定”——避免 JIT 编译抖动和 GC 压力波动。
- 典型提升:10–30% 吞吐量(
Serialize),反序列化可达 2× 以上(尤其含集合或深层嵌套时) - 真正关键收益是首次调用无 JIT 延迟:反射路径首次
Serialize<t></t>可能卡住 5–20ms;源生成代码在编译时就产出 IL,启动即可用 - 不适合场景:类型结构高度动态(如配置驱动的 JSON Schema)、开发期频繁改模型(每次改都要 rebuild 才能更新生成代码)、或仅偶尔序列化大文件(此时 IO 或压缩才是瓶颈)
- 调试时注意:生成的代码在
obj/下,VS 默认不加载,需在调试设置中启用 “Enable source server support” 并勾选 “Enable Just My Code” 外的符号加载,否则断点进不到生成方法里









