用于深层嵌套对象的自定义Json Serializer

时间:2017-12-14 00:24:31

标签: c# .net json serialization json.net

我有几个生成的.NET类有三个级别,我想以特殊格式序列化它们。所以,我开始使用Newtonsoft.Json编写一个自定义的Json Serializer。

我认为很难完全解释,所以我在此处发布了代码以及目标:https://dotnetfiddle.net/CDGcMW

基本上,有一个包含对象的初始数组,并且会有该对象的属性。困难的部分是这些属性未知,因此我尝试创建自定义序列化器。

任何帮助确定我如何在这里制作Json https://dotnetfiddle.net/CDGcMW成为"目标"我们非常感谢JSON的评论。

编辑:将dotnetfiddle更新为更小的示例。原文在这里:https://dotnetfiddle.net/dprfDu

2 个答案:

答案 0 :(得分:3)

你的目标" JSON处理起来很棘手,因为SubDataMappers列表的处理方式不同,具体取决于子项是否具有非空DataMapperProperty或非SubDataMappers列表。在前一种情况下,您希望将其呈现为每个子DataMapper包含一个属性的对象;在后者中,作为一个对象数组,每个对象包含一个DataMapper。此外,我发现您使用Name的{​​{1}}属性作为JSON中的键,而不是知名属性的值。鉴于这两个限制,我认为最好的攻击计划是使DataMapperJsonConverter列表上运行而不是单个实例。否则,转换器代码将变得相当混乱。如果这是可以接受的,那么以下转换器应该给你你想要的东西:

DataMappers

假设:

  • 您永远不会自行序列化单个public class DataMapperListConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(List<DataMapper>); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { List<DataMapper> list = (List<DataMapper>)value; if (list.Any(dm => dm.DataMapperProperty != null)) { JObject obj = new JObject(list.Select(dm => { JToken val; if (dm.DataMapperProperty != null) val = JToken.FromObject(dm.DataMapperProperty, serializer); else val = JToken.FromObject(dm.SubDataMappers, serializer); return new JProperty(dm.Name, val); })); obj.WriteTo(writer); } else { serializer.Serialize(writer, list.Select(dm => new Dictionary<string, List<DataMapper>> { { dm.Name, dm.SubDataMappers } })); } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Object) { return token.Children<JProperty>() .Select(jp => { DataMapper mapper = new DataMapper { Name = jp.Name }; JToken val = jp.Value; if (val["data-type"] != null) mapper.DataMapperProperty = jp.Value.ToObject<DataMapperProperty>(serializer); else mapper.SubDataMappers = jp.Value.ToObject<List<DataMapper>>(serializer); return mapper; }) .ToList(); } else if (token.Type == JTokenType.Array) { return token.Children<JObject>() .SelectMany(jo => jo.Properties()) .Select(jp => new DataMapper { Name = jp.Name, SubDataMappers = jp.Value.ToObject<List<DataMapper>>(serializer) }) .ToList(); } else { throw new JsonException("Unexpected token type: " + token.Type.ToString()); } } } ;它将始终包含在列表中。
  • DataMapper可以嵌套到任意深度。
  • DataMappers将始终具有非空DataMapper,这在每个级别都是唯一的。
  • Name永远不会同时包含非空DataMapper和非空DataMapperProperty列表。
  • SubDataMappers将始终具有非空DataMapperProperty
  • DataType永远不会有DataMapper Name

如果最后四个假设不成立,则此JSON格式不适用于您尝试执行的操作,您需要重新考虑。

要使用转换器,您需要将其添加到序列化设置中,如下所示。在序列化和反序列化时使用这些设置。从data-type类中删除[JsonConverter]属性。

DataMapper

这是一个往返演示:https://dotnetfiddle.net/8KycXB

答案 1 :(得分:0)

您可以使用ExpandoObject替换所有类型的类,从而使用JSON.NET实现深层嵌套序列化。这个对我有用。让我知道它是否适合您或需要任何样本来向您展示。

更新:

这是工作样本

https://dotnetfiddle.net/jtebDs

希望这是你想看到的输出。如果您有任何问题,请告诉我。