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

System.Text.Json无法反序列化JSON至泛型类的问题排查

问题:Changed反序列化失败的解决办法

代码定义

抽象类、泛型类及枚举

public abstract class Changed
{
    public abstract object OldValue { get; set; }
    public abstract object NewValue { get; set; }
    public TrackedPropertyType Type { get; set; }
}
    
public class Changed<T> : Changed
{
    public override object OldValue { get; set; }
    public override object NewValue { get; set; }
    
    public Changed(T oldValue, T newValue, TrackedPropertyType type)
    {
        OldValue = oldValue;
        NewValue = newValue;
        Type = type;
    }
}

public enum TrackedPropertyType
{
    PhoneNumber,
    Name,
    Email,
    BirthDate,
    WorkedInDodo,
    SocialNetworkMessagingEnable,
    IsKeyWord,
    IsBanned,
    IsFraud,
    IsRemove,
}

序列化后的JSON示例

{"type": 6, "newValue": 1, "oldValue": 2}

或

{"type": 5, "newValue": true, "oldValue": true}

反序列化代码及异常

反序列化代码:

JsonSerializer.Deserialize<Changed<string>>(json, options);

抛出异常:

System.InvalidOperationException: 反序列化类型'Dodo.Control.Ratings.Model.MysteryShoppers.Events.Changed`1[System.Boolean]'的构造器时,每个参数必须绑定到对象的属性或字段。每个参数名称必须与对象的属性或字段匹配。仅当启用'JsonSerializerOptions.IncludeFields'时才会考虑字段。匹配不区分大小写。

当前JsonSerializerOptions配置

  • PropertyNameCaseInsensitive: true
  • JsonCamelCaseNamingPolicy: JsonCamelCaseNamingPolicy

解决方案

方法1:添加无参数构造函数

System.Text.Json默认优先使用有参构造函数,但当构造参数无法与JSON属性正确绑定时会报错。给Changed<T>添加无参构造后,序列化器会直接通过属性赋值完成反序列化:

public class Changed<T> : Changed
{
    public override object OldValue { get; set; }
    public override object NewValue { get; set; }
    
    // 添加无参数构造函数
    public Changed() { }

    public Changed(T oldValue, T newValue, TrackedPropertyType type)
    {
        OldValue = oldValue;
        NewValue = newValue;
        Type = type;
    }
}

方法2:标记构造函数并明确参数映射

如果不想添加无参构造,可给现有有参构造添加[JsonConstructor]属性,并通过[JsonPropertyName]明确参数与JSON键的映射关系,确保序列化器能正确绑定:

using System.Text.Json.Serialization;

public class Changed<T> : Changed
{
    public override object OldValue { get; set; }
    public override object NewValue { get; set; }
    
    [JsonConstructor]
    public Changed(
        [JsonPropertyName("oldValue")] T oldValue, 
        [JsonPropertyName("newValue")] T newValue, 
        [JsonPropertyName("type")] TrackedPropertyType type)
    {
        OldValue = oldValue;
        NewValue = newValue;
        Type = type;
    }
}

方法3:重构为强类型属性(推荐)

原代码中父类用object类型属性,子类重写后通过泛型构造赋值,存在类型转换的潜在问题。重构为子类直接定义强类型属性,既能避免反序列化绑定问题,也让代码更清晰:

public abstract class Changed
{
    public TrackedPropertyType Type { get; set; }
}
    
public class Changed<T> : Changed
{
    public T OldValue { get; set; }
    public T NewValue { get; set; }
    
    public Changed() { }

    public Changed(T oldValue, T newValue, TrackedPropertyType type)
    {
        OldValue = oldValue;
        NewValue = newValue;
        Type = type;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 06:15:59