含私有列表的自定义集合类如何实现纯数组结构的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
相关产品推荐
相关产品推荐

