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

反序列化JSON至RequestWithDefault时虚拟集合字段元素重复问题

问题分析与解决方案

这个问题我之前也碰到过,核心要看你使用的序列化器类型,但本质都是反序列化过程中没有替换预先初始化的集合实例,而是把JSON中的元素追加到了已有的集合里,最终导致默认值"test"和JSON里的"f1"、"f2"共存,甚至触发重复元素的业务异常。

为什么会出现这个问题?

你的RequestWithDefault类里,Fields属性在声明时直接初始化了一个包含"test"的List<string>:

public override List<string> Fields {get; set; } = new List<string> {"test"}
  • 如果你用的是Newtonsoft.Json(Json.NET):它的默认行为是,只要集合属性已经有实例(比如你这里预先初始化的List),反序列化时就会把JSON数组的元素逐个追加进去,而不是创建新集合替换掉原有实例。
  • 如果你用的是DataContractSerializer:正常情况下,只要属性有public setter,它会创建新集合赋值给属性,但如果基类的virtual属性加上某些序列化配置,也可能出现集合被复用、元素追加的情况。

针对性解决方案

情况1:使用Newtonsoft.Json(Json.NET)

方案1:移除属性初始化器,让反序列化自动创建新集合

最简单的方式是去掉属性上的初始化代码,这样Json.NET会在反序列化时自动创建新的List<string>并填充JSON中的元素:

[DataContract] // 注意:这里应该是[DataContract]而非[DataContext],可能是笔误
public class RequestWithDefault : BaseRequest {
    [DataMember]
    public override List<string> Fields { get; set; }
}

如果需要在JSON未传入fields字段时保留默认的["test"],可以把初始化逻辑放到无参构造函数里,同时配置JsonProperty确保只有当JSON中没有该字段时才使用默认值:

using Newtonsoft.Json;

[DataContract]
public class RequestWithDefault : BaseRequest {
    public RequestWithDefault() {
        Fields = new List<string> {"test"};
    }

    [DataMember]
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public override List<string> Fields { get; set; }
}

方案2:自定义转换器强制替换集合

如果必须保留属性初始化器,可以写一个自定义JsonConverter,强制在反序列化时创建新集合替换原有实例:

public class ReplaceCollectionConverter<T> : JsonConverter<List<T>> {
    public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer) {
        // 忽略已有集合,直接从JSON读取新集合
        var newCollection = serializer.Deserialize<List<T>>(reader);
        return newCollection ?? new List<T>();
    }

    public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer) {
        serializer.Serialize(writer, value);
    }
}

然后把转换器应用到Fields属性上:

[DataMember]
[JsonConverter(typeof(ReplaceCollectionConverter<string>))]
public override List<string> Fields { get; set; } = new List<string> {"test"};

情况2:使用DataContractSerializer

如果用的是.NET自带的DataContractSerializer,只需要调整初始化逻辑的位置,把属性初始化器移到构造函数里即可:

[DataContract]
public class RequestWithDefault : BaseRequest {
    public RequestWithDefault() {
        Fields = new List<string> {"test"};
    }

    [DataMember]
    public override List<string> Fields { get; set; }
}

这样,当JSON中存在fields字段时,DataContractSerializer会创建新的集合实例赋值给Fields,覆盖构造函数的默认值;如果JSON中没有该字段,则保留默认的["test"]。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:33:04