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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用于深层嵌套对象的自定义Json Serializer相关的知识,希望对你有一定的参考价值。

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

我相信很难完全解释,所以我在这里发布了代码和目标:https://dotnetfiddle.net/CDGcMW

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

任何帮助确定我如何使这里生产的Json https://dotnetfiddle.net/CDGcMW成为被评论出来的“目标”JSON将不胜感激。

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

答案

你的“目标”JSON很难处理,因为SubDataMappers列表的处理方式不同,取决于孩子们是否有一个非空的DataMapperProperty或一个非空的SubDataMappers列表。在前一种情况下,您希望将其呈现为包含每个子项DataMapper的一个属性的对象;在后者中,作为一个包含一个DataMapper的对象数组。另外,我发现你使用NameDataMapper属性作为JSON中的关键而不是知名属性的值。鉴于这两个限制,我认为最好的攻击计划是制作一个JsonConverter,它运行在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将永远不会有一个非null的DataMapperProperty和一个非空的SubDataMappers列表。
  • 一个DataMapperProperty总是有一个非null的DataType
  • DataMapper永远不会有Namedata-type

如果最后四个假设不成立,那么这个JSON格式将不适用于你想要做的事情,你需要重新思考。

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

var settings = new JsonSerializerSettings()
{
    Converters = new List<JsonConverter> { new DataMapperListConverter() },
    Formatting = Formatting.Indented
};

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

另一答案

您可以使用ExpandoObject替换所有类型的类,从而使用JSON.NET实现深层嵌套序列化。这个对我有用。如果它适合您或需要任何样品来告诉我,请告诉我。

更新:

这是工作样本

https://dotnetfiddle.net/jtebDs

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

以上是关于用于深层嵌套对象的自定义Json Serializer的主要内容,如果未能解决你的问题,请参考以下文章

Json Schema:仅当深层嵌套对象中存在特定属性时才需要属性

遍历具有深层嵌套对象和数组的对象数组

来自 MYSQL PDO 的自定义格式 JSON,用于 NVD3.js

获取嵌套的自定义字段 JSON Objective C

在R中展平深层嵌套的json

如何通过 gson 将 json 反序列化为嵌套的自定义地图?