You need to enable JavaScript to run this app. 含私有列表的自定义集合类如何实现纯数组结构的Json序列化输出
优惠活动
大模型
产品
解决方案
定价
更多

含私有列表的自定义集合类如何实现纯数组结构的Json序列化输出

可行实现方式

完全可以通过适配Newtonsoft.Json的序列化规则,让PrivateListCollection直接输出无外层键包装的纯数组[1,2,3]结构,不需要让类本身去继承List。具体方案按落地优先级排序如下:

方案1:绑定专属JsonConverter(最稳定,无业务逻辑侵入)

这是最通用的实现方式,完全不需要改动原有类的Add方法、ISerializable实现等业务逻辑,只需要给类指定一个自定义序列化转换器,强制让它按数组格式输出内容。
第一步,编写对应类型的转换器:

public class PrivateListCollectionConverter : JsonConverter
{
    // 仅处理序列化场景,读取逻辑按需补充即可
    public override bool CanWrite => true;
    public override bool CanRead => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var instance = (PrivateListCollection)value;
        // 通过反射拿到类内部私有字段存储的列表
        var innerList = (List<int>)typeof(PrivateListCollection)
            .GetField("list", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
            .GetValue(instance);
        // 直接按JSON数组格式写入所有元素
        writer.WriteStartArray();
        foreach (var num in innerList)
        {
            writer.WriteValue(num);
        }
        writer.WriteEndArray();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

第二步,给PrivateListCollection类加上转换器绑定特性:

[Serializable]
[JsonConverter(typeof(PrivateListCollectionConverter))]
class PrivateListCollection: ISerializable
{
    // 原有业务逻辑完全保留,不需要做任何修改
    private List<int> list = new List<int>();
    public void Add(int value)
    {
        list.Add(value);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("items", list);
    }
}

完成绑定后,不管是直接序列化类实例,还是把类作为其他对象的属性嵌套序列化,都会稳定输出纯数组结构,不会被原有ISerializable的逻辑干扰生成带"items"键的对象。

方案2:实现枚举接口适配(适合可调整类结构的场景)

Newtonsoft.Json的默认规则里,实现了非字典类型IEnumerable接口的类,会被自动识别为数组类型处理。但这个方案有个绕不开的问题:因为你的类实现了ISerializable接口,Newtonsoft的序列化优先级里ISerializable的逻辑高于集合识别逻辑,如果不特意调整,还是会优先走ISerializable的路径输出带键的对象。
如果要走这个路径,需要做两个调整:

  • 给类实现IEnumerable<int>接口,把内部的list元素向外暴露枚举能力
  • 加特性阻止Newtonsoft优先走ISerializable的对象序列化逻辑
[Serializable]
[JsonObject(MemberSerialization.OptOut)]
class PrivateListCollection: ISerializable, IEnumerable<int>
{
    private List<int> list = new List<int>();
    public void Add(int value) => list.Add(value);
    // 新增枚举实现
    public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("items", list);
    }
}

这个方案的稳定性不如自定义转换器,容易受其他序列化配置的影响,更适合可以直接移除ISerializable实现的类。

原有输出的原因

你现在看到的{"items":[1,2,3]}结果,是Newtonsoft对实现ISerializable接口的类的默认适配逻辑:它会把GetObjectData方法里通过info.AddValue添加的所有键值对,当成普通对象的属性生成JSON结构,不会识别内部list本身是数组。
而继承自List的ListCollection因为本身是标准集合类型,没有实现ISerializable接口,默认就会被识别为数组序列化,自然输出无包装的纯数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.12 16:15:10