无法反序列化当前JSON对象(空数组) [英] Cannot Deserialize the Current JSON Object (Empty Array)
问题描述
我试图使该程序将所有这些对象格式化为树状视图,以实现此目的(我使用JSON排序对象),我需要解析JSON,所以我选择了JSON.NET.
I am trying to make this program that formats all these objects into a treeview, to do this (I'm using JSON for ordering the objects), I needed to parse the JSON, so I chose JSON.NET.
下面是格式设置的一个示例:
So here is an example of how the formatting is:
{
"Space": {
"ClassName": "SpaceObject",
"Name": "Space",
"Children": {
"Object1": {
"ClassName": "Object",
"Name": "Object1",
"Children": []
},
"Object2": {
"ClassName": "Object",
"Name": "Object2",
"Children": []
}
}
}
}
public class CObject
{
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ClassName")]
public string ClassName { get; set; }
[JsonProperty(PropertyName = "Children")]
public IDictionary<string, CObject> Children { get; set; }
}
IDictionary<string, CObject> obj = JsonConvert.DeserializeObject<IDictionary<string, CObject>>(Json, new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
});
foreach (var i in obj) {
ExplorerView1.Nodes.Add(AddObject(i.Value));
}
我相信我发现了错误,这是由于其中没有对象的子数组所致.我不知道如何解决这个问题,有人可以帮忙吗?
I believe I found the error, it's due to a children array having no objects in it. I don't know how to fix this though, can anyone help?
推荐答案
JsonSingleOrEmptyArrayConverter<T>
从此答案到 在类型可以不同时反序列化JSON 几乎可以满足您的需求.只需对其进行增强,以使当前合同类型既可以是字典合同又可以是对象合同.
JsonSingleOrEmptyArrayConverter<T>
from this answer to Deserialize JSON when type can be different almost does what you need. It simply needs to be enhanced to allow the current contract type to be a dictionary contract as well as an object contract.
首先,如下修改JsonSingleOrEmptyArrayConverter<T>
:
public class JsonSingleOrEmptyArrayConverter<T> : JsonConverter where T : class
{
//https://stackoverflow.com/questions/29449641/deserialize-json-when-type-can-be-different?rq=1
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
// Allow for dictionary contracts as well as objects contracts, since both are represented by
// an unordered set of name/value pairs that begins with { (left brace) and ends with } (right brace).
if (!(contract is Newtonsoft.Json.Serialization.JsonObjectContract
|| contract is Newtonsoft.Json.Serialization.JsonDictionaryContract))
{
throw new JsonSerializationException(string.Format("Unsupported objectType {0} at {1}.", objectType, reader.Path));
}
switch (reader.SkipComments().TokenType)
{
case JsonToken.StartArray:
{
int count = 0;
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
case JsonToken.EndArray:
// You might want to allocate an empty object here if existingValue is null
// If so, do
// return existingValue ?? contract.DefaultCreator();
return existingValue;
default:
{
count++;
if (count > 1)
throw new JsonSerializationException(string.Format("Too many objects at path {0}.", reader.Path));
existingValue = existingValue ?? contract.DefaultCreator();
serializer.Populate(reader, existingValue);
}
break;
}
}
// Should not come here.
throw new JsonSerializationException(string.Format("Unclosed array at path {0}.", reader.Path));
}
case JsonToken.Null:
return null;
case JsonToken.StartObject:
existingValue = existingValue ?? contract.DefaultCreator();
serializer.Populate(reader, existingValue);
return existingValue;
default:
throw new InvalidOperationException("Unexpected token type " + reader.TokenType.ToString());
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
}
然后反序列化如下:
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
Converters = { new JsonSingleOrEmptyArrayConverter<IDictionary<string, CObject>>() },
};
var obj = JsonConvert.DeserializeObject<IDictionary<string, CObject>>(Json, settings);
注意:
-
我的假设是,仅当没有子级时才使用空数组
[]
.如果该数组曾经是非空数组,则此假设将是错误的,并且转换器将无法正常工作.
My assumption is that an empty array
[]
is only used when there are no children. If the array is ever nonempty, this assumption will be wrong and the converter will not work correctly.
转换器为空数组返回null
值.如果您想改用空字典,请取消注释以下几行:
The converter returns a null
value for an empty array. If you would instead prefer an empty dictionary, uncomment the following lines:
// You might want to allocate an empty object here if existingValue is null
// If so, do
// return existingValue ?? contract.DefaultCreator();
正在工作的.Net小提琴此处.
Working .Net fiddle here.
这篇关于无法反序列化当前JSON对象(空数组)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!