我正在尝试从第三方服务反序列化json
{
"route1":[
{
"Id":1
}
],
"route2":{
"error":"Id not found"
}
}
它是一个Dictionary
,但值可以是数组或对象。我需要唯一的数组,所以当我在JsonConverter
中找到一个对象时,我决定放一个空数组。
public class Item
{
public int Id { get; set; }
}
public class JsonInfo
{
[JsonConverter(typeof(ItemConverter))]
public List<Item> Items{ get; set; }
}
public class ItemConverter : Newtonsoft.Json.JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
case JsonToken.StartObject:
return new List<Item>();
case JsonToken.StartArray:
var array = JArray.Load(reader);
var data = array.Select(ParseValue).ToList();
return data;
default:
return null;
}
}
public override bool CanConvert(Type objectType)
{
return false;
}
private Item ParseValue(JToken value)
{
switch (value.Type)
{
case JTokenType.Object:
return value.ToObject<Item>();
default:
return null;
}
}
}
但当我试图反序列化Dictionary<string, JsonInfo>
时,它会引发一个错误(必须是json数组(。我认为转换器试图在json中找到JsonInfo
属性,而不是在这个类中找到数组的问题。
也许我错过了什么
我们有允许跳过属性名称的属性吗?
您不需要创建自定义转换器。
您可以通过以下几行代码实现相同的功能:
var semiParsedJson = JObject.Parse(rawJson);
var result = new Dictionary<string, List<Item>>();
foreach (var item in semiParsedJson)
if (item.Value is JArray)
result.Add(item.Key, item.Value.ToObject<List<Item>>());
else
result.Add(item.Key, new List<Item>>());
- 我们将json半解析为
JObject
- 我们通过一个简单的foreach迭代其属性,其中项的类型为
KeyValuePair<string, JToken?>
- 如果
Value
是JArray
(而不是JObject
(,那么我们简单地用Value
的内容填充字典 - 最后,我们让Newtonsoft代表我们将
Value
转换为List<Item>
集合
使用这种方法,您不需要编写自定义转换器,也不需要用序列化属性装饰域模型。
我解决了我的问题,不是将自定义转换器应用于属性,而是应用于整个类
[JsonConverter(typeof(ItemConverter))]
public class JsonInfo
{
public List<Item> Items{ get; set; }
}
public class ItemConverter: JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
return null;
case JsonToken.StartObject:
reader.Skip();
return new JsonInfo{ Items = new List<Item>() };
case JsonToken.StartArray:
var array = JArray.Load(reader);
var data = array.Select(ParseValue).ToList();
return new JsonInfo{ Items = data };
default:
return null;
}
}
public override bool CanConvert(Type objectType)
{
return false;
}
private Item ParseValue(JToken value)
{
switch (value.Type)
{
case JTokenType.Object:
return value.ToObject<Item>();
default:
return null;
}
}
}