You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用System.Text.Json源代码生成器时序列化/反序列化随机失败排查

问题概述

基于FNA框架(C#非Unity)开发包含复杂嵌套对象数据库的游戏,为适配Native AOT环境,计划从Newtonsoft.Json迁移至System.Text.Json。启用源代码生成器时,序列化/反序列化随机出现不完整现象(部分对象正常、部分异常);禁用生成器可正常序列化/反序列化,但无法适配Native AOT。

Newtonsoft.Json配置(Native AOT可运行但速度较慢)

public static JsonSerializerSettings settings = new JsonSerializerSettings
{
    Formatting = Newtonsoft.Json.Formatting.None,
    TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto,
    DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.IgnoreAndPopulate,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
    ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace,

    Error = (sender, args) =>
    {
        args.ErrorContext.Handled = true;
        Console.WriteLine("JsonDeserialize Error: ***" + args.ErrorContext.Error.Message);
    }
};

System.Text.Json配置

public static JsonSerializerOptions jbinSerializerOption = new JsonSerializerOptions
{
    WriteIndented = false, // 保持false以减小JSON体积
    PropertyNameCaseInsensitive = false,
    DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault, // 忽略默认值减小体积
    IncludeFields = true,
    ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles,
    TypeInfoResolver = Core_JsonContext.Default, // 注释此行则禁用源代码生成器
};

源代码生成器类定义

[JsonSourceGenerationOptions(  // 源代码生成器参数
    WriteIndented = false,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    GenerationMode = JsonSourceGenerationMode.Default,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
    IncludeFields = true
)]
[JsonSerializable(typeof(Data_Zone))]
[JsonSerializable(typeof(Data_PageCredit))]
[JsonSerializable(typeof(AstralDBSystemLoader))]
[JsonSerializable(typeof(AstralDataBaseLoader))]
[JsonSerializable(typeof(Microsoft.Xna.Framework.Color))]
[JsonSerializable(typeof(Microsoft.Xna.Framework.Rectangle))]
[JsonSerializable(typeof(Microsoft.Xna.Framework.Vector2))]
[JsonSerializable(typeof(Microsoft.Xna.Framework.Vector3))]
[JsonSerializable(typeof(Microsoft.Xna.Framework.Vector4))]
[JsonSerializable(typeof(CoreBD.Core_Bitmap))]
[JsonSerializable(typeof(CoreBD.Core_Sprite))]
[JsonSerializable(typeof(CoreBD.Core_Sequence))]
[JsonSerializable(typeof(CoreBD.Core_Clip))]
[JsonSerializable(typeof(CoreBD.Core_ClipEtatMouv))]
[JsonSerializable(typeof(CoreBD.Core_ClipImgCle))]
[JsonSerializable(typeof(CoreBD.Core_ClipRoute))]
[JsonSerializable(typeof(CoreBD.Core_ClipImgCleAction))]
[JsonSerializable(typeof(CoreBD.Core_IANeurone))]
[JsonSerializable(typeof(CoreBD.Data_Zone))] // 重复注册了Data_Zone类型
[JsonSerializable(typeof(CoreBD.Core_ParamZone))]

public partial class Core_JsonContext : JsonSerializerContext // 源代码生成器入口
{
}

异常场景

执行以下克隆逻辑时,启用生成器会得到空对象或不完整对象:

string copieText = System.Text.Json.JsonSerializer.Serialize(source, jbinSerializerOptionTriche);
return System.Text.Json.JsonSerializer.Deserialize<T>(copieText, jbinSerializerOption);

奇怪现象:无生成器序列化的数据库文件,可通过生成器正常反序列化,但运行时克隆场景失效。


问题分析与解决方案

1. 配置不一致问题

  • 生成器与运行时配置不匹配:生成器配置中设置了PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,但运行时jbinSerializerOption未指定命名策略且PropertyNameCaseInsensitive = false,导致序列化用驼峰命名、反序列化严格匹配原属性名,最终丢失数据。
  • 重复注册类型:生成器中重复添加[JsonSerializable(typeof(Data_Zone))]和[JsonSerializable(typeof(CoreBD.Data_Zone))],可能导致生成器混淆,生成错误的序列化逻辑。

2. 多态类型处理缺失

Newtonsoft.Json通过TypeNameHandling.Auto自动处理多态类型,但System.Text.Json源代码生成器默认不支持多态。若嵌套对象包含多态结构(如基类引用子类实例),生成器无法识别子类类型,会导致序列化/反序列化不完整。

3. 克隆逻辑的配置差异

克隆代码中使用jbinSerializerOptionTriche序列化,却用jbinSerializerOption反序列化。若两个配置存在差异(如一个启用生成器、一个未启用,或命名策略不同),必然导致数据不匹配。

4. 对象创建与循环引用处理差异

Newtonsoft.Json的ObjectCreationHandling.Replace对应System.Text.Json的ReferenceHandler.IgnoreCycles,但生成器对复杂嵌套对象的循环引用处理需显式配置,否则可能出现对象创建异常。


修复步骤

  1. 统一配置参数
    确保JsonSourceGenerationOptions与JsonSerializerOptions配置完全一致,同时删除重复的类型注册:
// 生成器配置
[JsonSourceGenerationOptions(
    WriteIndented = false,
    PropertyNamingPolicy = null, // 取消驼峰命名,与运行时配置对齐
    GenerationMode = JsonSourceGenerationMode.Default,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
    IncludeFields = true,
    ReferenceHandler = ReferenceHandler.IgnoreCycles // 添加循环引用处理,与运行时对齐
)]
// 删除重复的[JsonSerializable(typeof(Data_Zone))]注册

// 运行时配置
public static JsonSerializerOptions jbinSerializerOption = new JsonSerializerOptions
{
    WriteIndented = false,
    PropertyNameCaseInsensitive = false,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
    IncludeFields = true,
    ReferenceHandler = ReferenceHandler.IgnoreCycles,
    TypeInfoResolver = Core_JsonContext.Default
};
  1. 添加多态支持
    对需要多态处理的基类,在生成器中显式声明子类类型:
// 示例:假设BaseClass是基类,Derived1、Derived2是子类
[JsonSerializable(typeof(BaseClass), TypeInfoPropertyName = "BaseClass")]
[JsonDerivedType(typeof(Derived1), typeDiscriminator: "Derived1")]
[JsonDerivedType(typeof(Derived2), typeDiscriminator: "Derived2")]
  1. 统一克隆逻辑的配置
    确保序列化和反序列化使用相同的配置:
string copieText = System.Text.Json.JsonSerializer.Serialize(source, jbinSerializerOption);
return System.Text.Json.JsonSerializer.Deserialize<T>(copieText, jbinSerializerOption);
  1. 检查成员可访问性
    确保所有需要序列化的字段/属性为public,或用[JsonInclude]特性标记非公共成员。源代码生成器对非公共成员的处理需显式配置,灵活性低于反射模式。

  2. 启用调试排查
    添加调试日志或跟踪生成的序列化代码,查看是否有字段遗漏或错误:

  • 可自定义转换器输出序列化过程的详细信息
  • 查看生成的Core_JsonContext代码,确认是否所有需要序列化的成员都被正确处理

内容的提问来源于stack exchange,提问作者fenryo237

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:20:31