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

C#中Record的复杂JSON序列化与反序列化问题

问题原因分析

当你给AmountPayed标记[JsonConverter(typeof(AmountPayedConverter))]后,序列化MyObject时,JsonSerializer会先为AmountPayed属性写入键名"AmountPayed":,再调用自定义转换器的Write方法。但你的转换器直接向写入器输出了"Currency"和"Amount"两个键值对,导致JSON结构变成"AmountPayed": "Currency": "EUR", "Amount": 1000——这完全违反JSON语法规则,既生成了无效JSON,又保留了多余的AmountPayed字段。

解决方案

要实现将AmountPayed的属性平级嵌入MyObject的JSON结构中,需要从父对象层面控制序列化逻辑,以下是两种可行方案:

方案一:为MyObject编写自定义转换器

通过自定义MyObject的序列化逻辑,直接将AmountPayed的属性展开到根JSON对象中:

[JsonConverter(typeof(MyKeyConverter))]
record MyKey(Guid Value);

record AmountPayed(string Currency, decimal Value);

[JsonConverter(typeof(MyObjectConverter))]
record MyObject(MyKey Id, string Name, AmountPayed AmountPayed);

class MyKeyConverter : JsonConverter<MyKey>
{
    public override MyKey Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, MyKey value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.Value);
    }
}

class MyObjectConverter : JsonConverter<MyObject>
{
    public override MyObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 如需反序列化,可在此处补全逻辑:读取Currency和Amount构造AmountPayed,再构造MyObject
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, MyObject value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        
        // 序列化Id(复用MyKey的转换器)
        writer.WritePropertyName("Id");
        JsonSerializer.Serialize(writer, value.Id, options);
        
        // 序列化Name
        writer.WriteString("Name", value.Name);
        
        // 展开AmountPayed的属性
        writer.WriteString("Currency", value.AmountPayed.Currency);
        writer.WriteNumber("Amount", value.AmountPayed.Value);
        
        writer.WriteEndObject();
    }
}

序列化后得到的JSON符合预期:

{
  "Id": "0748f992-4187-4006-98ed-d5cb0355f99c",
  "Name": "My Name",
  "Currency": "EUR",
  "Amount": 1000
}

方案二:结合JsonIgnore与计算属性

利用Record的特性,添加映射到AmountPayed属性的计算字段,同时忽略原AmountPayed属性:

[JsonConverter(typeof(MyKeyConverter))]
record MyKey(Guid Value);

record AmountPayed(string Currency, decimal Value);

record MyObject(MyKey Id, string Name, AmountPayed AmountPayed)
{
    [JsonPropertyName("Currency")]
    public string Currency => AmountPayed.Currency;
    
    [JsonPropertyName("Amount")]
    public decimal Amount => AmountPayed.Value;
    
    [JsonIgnore]
    public AmountPayed AmountPayed => AmountPayed;
}

class MyKeyConverter : JsonConverter<MyKey>
{
    public override MyKey Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, MyKey value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.Value);
    }
}

这种方式无需编写复杂的转换器,仅通过属性标记即可实现平级序列化,适合简单场景。

内容的提问来源于stack exchange,提问作者Paulo Aboim Pinto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:13:28