您的“目标”JSON 处理起来很棘手,因为 SubDataMappers 列表的处理方式会有所不同,具体取决于子级是具有非空 DataMapperProperty 还是非空 SubDataMappers 列表。在前一种情况下,您希望它呈现为一个对象,每个子对象都包含一个属性DataMapper;在后者中,作为一个对象数组,每个对象包含一个DataMapper。另外,我看到您使用 DataMapper 的 Name 属性作为 JSON 中的键,而不是作为众所周知的属性的值。考虑到这两个限制,我认为最好的攻击计划是创建一个在DataMappers 的列表 上运行的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 将始终有一个非空的 Name,它在每个级别都是唯一的。
-
DataMapper 永远不会同时具有非空 DataMapperProperty 和非空列表 SubDataMappers。
-
DataMapperProperty 将始终有一个非空的 DataType。
-
DataMapper 永远不会有 Name 或 data-type。
如果最后四个假设不成立,那么这种 JSON 格式将不适用于您正在尝试做的事情,您需要重新考虑。
要使用转换器,您需要将其添加到您的序列化程序设置中,如下所示。在序列化和反序列化时都使用这些设置。从DataMapper 类中删除[JsonConverter] 属性。
var settings = new JsonSerializerSettings()
{
Converters = new List<JsonConverter> { new DataMapperListConverter() },
Formatting = Formatting.Indented
};
这是一个往返演示:https://dotnetfiddle.net/8KycXB