如何用Newtonsoft序列化泛型类且不封装内部类型
问题:Newtonsoft.Json序列化时展开Generic的Data属性,避免嵌套
现有泛型类和实体类定义如下:
public class Generic<T> where T : class { public bool IsSuccess { get; set; } public string Message { get; set; } public T Data { get; set; } } public class Specific { public string Name { get; set; } public int Id { get; set; } }
声明对象示例:
var wrappedSpecific = new Generic<Specific> { IsSuccess = true, Message = "Success", Data = new Specific { Name = "Test", Id = 1, } };
默认序列化会得到嵌套格式:
{"IsSuccess":true,"Message":"Success","Data":{"Name":"Test","Id":1}}
需求:希望序列化时将Data属性内的字段直接平级输出,得到如下格式,且不采用Specific : Generic的继承方式,保证Specific类可独立复用:
{"IsSuccess":true,"Message":"Success","Name":"Test","Id":1}
解决方案:自定义JsonConverter
通过实现JsonConverter来控制序列化逻辑,将Generic<T>的基础属性和Data内的属性合并输出:
通用转换器代码
public class GenericConverter : JsonConverter { // 判断当前类型是否为Generic<T> public override bool CanConvert(Type objectType) { return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Generic<>); } // 自定义序列化逻辑 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var genericType = value.GetType(); // 获取Generic<T>自身的属性(排除Data) var baseProperties = genericType.GetProperties() .Where(p => p.Name != nameof(Generic<object>.Data)); // 获取Data属性的值 var dataProp = genericType.GetProperty(nameof(Generic<object>.Data)); var dataValue = dataProp.GetValue(value); writer.WriteStartObject(); // 序列化Generic<T>的基础属性 foreach (var prop in baseProperties) { writer.WritePropertyName(prop.Name); serializer.Serialize(writer, prop.GetValue(value)); } // 序列化Data对象的所有属性(如果Data不为null) if (dataValue != null) { var dataType = dataValue.GetType(); foreach (var dataProperty in dataType.GetProperties()) { writer.WritePropertyName(dataProperty.Name); serializer.Serialize(writer, dataProperty.GetValue(dataValue)); } } writer.WriteEndObject(); } // 反序列化逻辑可根据需求实现(以下为示例框架) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var genericInstance = Activator.CreateInstance(objectType); var dataType = objectType.GetGenericArguments()[0]; var dataInstance = Activator.CreateInstance(dataType); var jsonObject = JObject.Load(reader); // 给Generic<T>的基础属性赋值 foreach (var prop in objectType.GetProperties().Where(p => p.Name != nameof(Generic<object>.Data))) { var value = jsonObject[prop.Name]?.ToObject(prop.PropertyType, serializer); prop.SetValue(genericInstance, value); } // 给Data对象的属性赋值 foreach (var prop in dataType.GetProperties()) { var value = jsonObject[prop.Name]?.ToObject(prop.PropertyType, serializer); prop.SetValue(dataInstance, value); } // 将Data对象赋值给Generic<T>的Data属性 objectType.GetProperty(nameof(Generic<object>.Data)).SetValue(genericInstance, dataInstance); return genericInstance; } }
使用方式
序列化时传入自定义转换器:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new GenericConverter()); var json = JsonConvert.SerializeObject(wrappedSpecific, settings); // 输出结果:{"IsSuccess":true,"Message":"Success","Name":"Test","Id":1}
说明
- 该转换器支持所有
Generic<T>类型,无需为每个实体类单独编写逻辑 - 若不需要反序列化,可省略
ReadJson方法的实现(或抛出NotImplementedException) - 保持了
Specific类的独立性,可在不需要Generic<T>包装的场景中直接复用
内容的提问来源于stack exchange,提问作者MPelletier
相关产品推荐
相关产品推荐

