C#继承List<T>的自定义类序列化JSON时丢失自定义属性问题
根本原因
你使用的Newtonsoft.Json序列化框架对继承了集合类型(比如List<T>、IEnumerable<T>)的类有默认处理逻辑:会将其识别为纯集合,仅序列化集合内的元素,忽略类上自定义的额外属性,这就是Reason字段丢失的核心原因。
另外需要提前明确:JSON规范中数组结构本身不支持附加自定义键值对属性,所以要保留Reason字段的话,序列化结果必然要调整为「对象包裹数组」的结构,无法做到既是纯数组又带额外属性。
兼容解决方案
以下方案均可以最大程度保留原有类结构和业务逻辑:
方案1:仅修改序列化调用代码(完全不改动原有类定义,兼容性最高)
如果仅需要序列化输出带Reason,不需要反序列化为FooList类型,直接用匿名类包裹原对象即可,只改动序列化一行代码:
// 原有业务逻辑完全不变 var foo = new Foo { Name = "foo1" }; var foo2 = new Foo { Name = "foo2" }; var foos = new List<Foo> { foo, foo2 }; var fooList = new FooList(); fooList.Reason = "Strange"; fooList.AddRange(foos); // 仅修改序列化这一行 var jsonFoo = JsonConvert.SerializeObject(new { fooList.Reason, Items = fooList });
序列化输出结果为:
{"Reason":"Strange","Items":[{"Name":"foo1"},{"Name":"foo2"}]}
方案2:少量修改FooList定义(适配序列化+反序列化场景,原有业务调用完全无感知)
给FooList加上强制按对象序列化的特性,额外暴露集合元素属性即可,原有所有对FooList的集合操作(Add、遍历、作为List<Foo>传参等)都完全不受影响:
// 加特性强制按普通对象序列化 [Newtonsoft.Json.JsonObject] public class FooList:List<Foo> { public string Reason { get; set; } // 私有属性不对外暴露,仅用于序列化输出集合元素 [Newtonsoft.Json.JsonProperty(nameof(Items))] private List<Foo> Items => this; }
修改后原有序列化代码不需要任何改动,输出结果和方案1一致,同时支持反序列化直接转回FooList对象。
方案3:自定义JsonConverter(完全不改动原有类定义,同时支持序列化反序列化)
如果连FooList的定义都不想改,可以自定义序列化转换器,全局或单独指定给FooList使用即可,适合FooList已经在大量场景引用,完全不能改类定义的场景:
public class FooListConverter : JsonConverter<FooList> { public override void WriteJson(JsonWriter writer, FooList value, JsonSerializer serializer) { writer.WriteStartObject(); writer.WritePropertyName(nameof(FooList.Reason)); serializer.Serialize(writer, value.Reason); writer.WritePropertyName("Items"); serializer.Serialize(writer, value.ToList()); writer.WriteEndObject(); } public override FooList ReadJson(JsonReader reader, Type objectType, FooList existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); var reason = jObj[nameof(FooList.Reason)]?.ToString(); var items = jObj["Items"]?.ToObject<List<Foo>>() ?? new List<Foo>(); var res = new FooList { Reason = reason }; res.AddRange(items); return res; } }
使用时指定转换器即可:
var jsonFoo = JsonConvert.SerializeObject(fooList, new FooListConverter());
内容的提问来源于stack exchange,提问作者ezycoder
相关产品推荐
相关产品推荐

