我正在使用此调用来读在JSON的对象列表中:
Rootobject userInfo = JsonConvert.DeserializeObject<Rootobject>(File.ReadAllText(strFileName));
但是我得到了一个例外Cannot deserialize the current JSON array
。如果类对象之一中的一个数组为空。只要有数据,一切都可以。
这是JSON的一个示例,它正在绊倒Deserializer:
这是场地对象的正常数据类型:
"venue": {
"venue_id": 696895,
"venue_name": "Blackfinn Ameripub",
"venue_slug": "blackfinn-ameripub",
"primary_category": "Food",
"parent_category_id": "4d4b7105d754a06374d81259",
"categories": {
"count": 1,
"items": [
{
"category_name": "American Restaurant",
"category_id": "4bf58dd8d48988d14e941735",
"is_primary": true
}
]
},
"is_verified": false
},
这是导致例外的原因,一个空数组:
"venue": [
],
我尝试使用JsonSerializerSettings
选项,包括DefaultValueHandling
,NullValueHandling
和MissingMemberHandling
,但它们似乎都没有阻止错误。
任何想法如何应对JSON,而只是忽略数据中的任何空数组?我希望这样处理任何空数组,而不仅仅是上面的对象Venue
。
发现了新问题-03/17/2018&lt;
嗨,下面的转换器运行良好,但是我正在从另一个挑战中获得JSON响应的服务器。JSON.NET检索此类数据没有问题:
"toasts": {
"total_count": 1,
"count": 1,
"auth_toast": false,
"items": [
{
"uid": 3250810,
"user": {
"uid": 3250810,
"account_type": "user",
"venue_details": [
],
"brewery_details": [
]
},
"like_id": 485242625,
"like_owner": false,
"created_at": "Wed, 07 Mar 2018 07:54:38 +0000"
}
]
},
特别是具有VENUE_DETAILS的部分。99%的响应带有这种格式的Verue_detail:
"venue_details": [
],
,但随后我突然得到了这种格式:
"toasts": {
"total_count": 1,
"count": 1,
"auth_toast": false,
"items": [
{
"uid": 4765742,
"user": {
"uid": 4765742,
"account_type": "venue",
"venue_details": {
"venue_id": 4759473
},
"brewery_details": [
],
"user_link": "https://untappd.com/venue/4759473"
},
"like_id": 488655942,
"like_owner": false,
"created_at": "Fri, 16 Mar 2018 16:47:10 +0000"
}
]
},
请注意,Venue_details现在如何具有价值并包括一个verue_id。
因此,venue_details最终看起来像一个对象而不是数组。这最终给出了这个例外:
jsonserialization exception:无法对当前的JSON对象(例如{" name":" value"}(进行当前的json对象(例如system.Collections.generic.generic.gener.list.1 [System.Object]',因为类型需要JSON数组(例如,[1,2,3](要正确地进行序列化。
在提供的转换器代码中,例外情况发生在此行中,旁边的 *s:
public abstract class IgnoreUnexpectedArraysConverterBase : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
if (!(contract is JsonObjectContract))
{
throw new JsonSerializationException(string.Format("{0} is not a JSON object", objectType));
}
do
{
if (reader.TokenType == JsonToken.Null)
return null;
else if (reader.TokenType == JsonToken.Comment)
continue;
else if (reader.TokenType == JsonToken.StartArray)
{
var array = JArray.Load(reader);
if (array.Count > 0)
throw new JsonSerializationException(string.Format("Array was not empty."));
return existingValue ?? contract.DefaultCreator();
}
else if (reader.TokenType == JsonToken.StartObject)
{
// Prevent infinite recursion by using Populate()
existingValue = existingValue ?? contract.DefaultCreator();
*** serializer.Populate(reader, existingValue); ***
return existingValue;
有什么想法如何添加此额外的处理以说明JSON返回对象而不是数组之间的翻转?
谢谢 里克
您的问题不是您需要忽略空数组。如果"items"
数组为空,则没有问题:
"items": [],
相反,您的问题如下。JSON标准支持两种类型的容器:
数组,这是一个有序的值集合。数组以
[
(左支架(开头,并以]
(右支架(结束。值通过,
(逗号(分开。对象,这是一组无序的名称/值对。一个对象以
{
(左支撑(开头,并以}
(右支撑(结尾。
由于某种原因,服务器正在返回一个空数组代替 null对象。如果JSON.NET期望遇到JSON对象,而是遇到JSON数组,它将抛出您看到的Cannot deserialize the current JSON array
例外。
您可能会考虑要求谁生成JSON修复其JSON输出,但是与此同时,您可以使用以下转换器在应对对象时跳过意外数组:
public class IgnoreUnexpectedArraysConverter<T> : IgnoreUnexpectedArraysConverterBase
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
}
public class IgnoreUnexpectedArraysConverter : IgnoreUnexpectedArraysConverterBase
{
readonly IContractResolver resolver;
public IgnoreUnexpectedArraysConverter(IContractResolver resolver)
{
if (resolver == null)
throw new ArgumentNullException();
this.resolver = resolver;
}
public override bool CanConvert(Type objectType)
{
if (objectType.IsPrimitive || objectType == typeof(string))
return false;
return resolver.ResolveContract(objectType) is JsonObjectContract;
}
}
public abstract class IgnoreUnexpectedArraysConverterBase : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
if (!(contract is JsonObjectContract))
{
throw new JsonSerializationException(string.Format("{0} is not a JSON object", objectType));
}
do
{
if (reader.TokenType == JsonToken.Null)
return null;
else if (reader.TokenType == JsonToken.Comment)
continue;
else if (reader.TokenType == JsonToken.StartArray)
{
var array = JArray.Load(reader);
if (array.Count > 0)
throw new JsonSerializationException(string.Format("Array was not empty."));
return null;
}
else if (reader.TokenType == JsonToken.StartObject)
{
// Prevent infinite recursion by using Populate()
existingValue = existingValue ?? contract.DefaultCreator();
serializer.Populate(reader, existingValue);
return existingValue;
}
else
{
throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
}
}
while (reader.Read());
throw new JsonSerializationException("Unexpected end of JSON.");
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后,如果空数组只能出现在对象图中的一个位置中,则可以将转换器添加到模型中:
public class Rootobject
{
[JsonConverter(typeof(IgnoreUnexpectedArraysConverter<Venue>))]
public Venue venue { get; set; }
}
但是,如您所说,任何对象可能被空数组替换,您可以使用非生成IgnoreUnexpectedArraysConverter
用于所有对象类型:
var resolver = new DefaultContractResolver(); // Cache for performance
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
Converters = { new IgnoreUnexpectedArraysConverter(resolver) },
};
var userInfo = JsonConvert.DeserializeObject<Rootobject>(jsonString, settings);
注意:
转换器不适用于
TypeNameHandling
或PreserveReferencesHandling
设置。转换器假设被估算的对象具有默认的构造函数。该对象具有一个参数化的构造函数,您需要创建一个硬编码转换器来分配和填充对象。
如果阵列不是空的,转换器会引发异常,以确保在对JSON结构的错误假设时没有数据丢失。有时,服务器会编写一个对象代替一个对象数组,而在有两个或多个对象时,将编写一个对象。如果您也处于这种情况(例如,对于
"items"
数组(,请参见如何使用JSON.NET 。。如果您希望转换器返回默认对象,而不是遇到数组时的
null
,请按以下方式更改它:else if (reader.TokenType == JsonToken.StartArray) { var array = JArray.Load(reader); if (array.Count > 0) throw new JsonSerializationException(string.Format("Array was not empty.")); return existingValue ?? contract.DefaultCreator(); }
工作样本.net小提琴。