深嵌套对象的自定义JSON序列化器



我有几个.NET类,它们会产生三个级别的深度,我想以特殊的格式序列化它们。因此,我开始使用newtonsoft.json编写自定义JSON序列化器。

我相信很难完全解释,因此我在此处发布了代码以及目标:https://dotnetfiddle.net/cdgcmw

本质上,有一个初始数组将包含对象,并且该对象将有属性。困难的部分是这些属性尚不清楚,因此就是为什么我尝试创建自定义序列化器的原因。

确定如何使我在这里生产的JSON的任何帮助https://dotnetfiddle.net/cdgcmw成为"目标" JSON,这将不胜感激。

编辑:将dotnetfiddle更新为一个较小的示例。原始内容:https://dotnetfiddle.net/dprfdu

您的"目标" JSON处理很难处理,因为SubDataMappers列表的处理是不同的,具体取决于孩子是否有非null DataMapperProperty还是SubDataMappers的非空名单。在前一种情况下,您希望它作为一个每个孩子DataMapper的物业的对象;在后者中,作为一个包含一个DataMapper的对象数组。另外,我看到您将DataMapperName属性用作JSON中的键,而不是作为知名属性的值。鉴于这两个约束,我认为最好的攻击计划是制作在DataMappers的A list 上运行的JsonConverter,而不是一个实例。否则,转换器代码将变得非常混乱。如果可以接受,那么以下转换器应该给您想要的东西:

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将始终具有非NULL Name,在每个级别上都是唯一的。
  • DataMapper永远不会同时拥有非挂钩DataMapperPropertySubDataMappers的非空列表。
  • DataMapperProperty将始终具有非弹药DataType
  • DataMapper永远不会有data-typeName

如果最后四个假设不正确,则这种JSON格式将无法为您尝试做的事情起作用,您将需要重新考虑。

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

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

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

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

更新:

这是工作样本

https://dotnetfiddle.net/jtebds

希望这是您希望看到的输出。让我知道您是否有任何疑问。

相关内容

  • 没有找到相关文章

最新更新