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

如何使用JSON.NET反序列化时保留现有只读集合与对象仅更新叶节点属性值

问题核心原因

你自定义的SubListConverter的ReadJson未触发,是因为Json.NET默认判定无setter的只读集合属性不可写入,直接跳过反序列化流程。同时默认的集合反序列化逻辑仅支持替换实例/追加元素两种模式,不支持按索引更新现有集合内对象的属性。

可行解决方案

你可以通过通用固定集合Json转换器+全局序列化配置实现需求,无需修改原有模型加注解:

1. 实现通用转换器

public class FixedSizeReadOnlyCollectionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // 匹配所有元素为类的ReadOnlyCollection<T>类型
        if (!objectType.IsGenericType) return false;
        var genericTypeDef = objectType.GetGenericTypeDefinition();
        if (genericTypeDef != typeof(ReadOnlyCollection<>)) return false;
        return objectType.GenericTypeArguments[0].IsClass;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 你的场景下existingValue一定不为空,为空直接跳过处理
        if (existingValue is not System.Collections.IList existingList)
        {
            reader.Skip();
            return existingValue;
        }

        // 读取JSON数组
        var jArray = JArray.Load(reader);
        // 按索引逐个填充现有对象的属性
        for (int i = 0; i < Math.Min(jArray.Count, existingList.Count); i++)
        {
            var existingElement = existingList[i];
            using var elementReader = jArray[i].CreateReader();
            serializer.Populate(elementReader, existingElement);
        }

        // 直接返回原有集合实例,不新建
        return existingValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 走默认序列化逻辑即可
        serializer.Serialize(writer, value);
    }
}

2. 调用时传入配置

无需修改原有模型,仅在调用PopulateObject时传入包含该转换器的配置即可:

var model1 = new MainModel();
model1.Subs[1].B = 5;
var json = JsonConvert.SerializeObject(model1);
var model2 = new MainModel();

// 构造序列化配置
var settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new FixedSizeReadOnlyCollectionConverter() }
};

JsonConvert.PopulateObject(json, model2, settings);

验证结果

执行后model2.Subs[1].B的值会被正确更新为5,完全满足你的要求:

  • 全程复用MainModel、ReadOnlyCollection<SubModel>、所有SubModel的现有实例
  • 无新对象、新集合实例创建
  • 仅更新SubModel的A、B叶节点属性
  • 无需修改原有模型加任何Json相关注解

扩展说明

如果你的场景还有其他固定大小的集合类型,只需修改CanConvert方法的匹配规则即可覆盖;如果需要校验JSON数组与现有集合长度一致性,可在ReadJson中增加判断抛出异常。


内容的提问来源于stack exchange,提问作者Sjoerd van Kreel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 19:24:05