在反序列化时如何忽略JSON对象数组中的空白数组?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在反序列化时如何忽略JSON对象数组中的空白数组?相关的知识,希望对你有一定的参考价值。

我正在使用Json.NET反序列化JSON。如何在反序列化期间忽略在对象数组中意外出现的空白数组?

我已在此网站http://json.parser.online.fr/上测试了第三方的以下JSON,确认其格式正确:

{
  "total_events": 3551574,
  "json.appID": [
    {
      "count": 3551024,
      "term": 1
    },
    {
      "count": 256,
      "term": 2
    },
    []                /* <----- I need to ignore this empty array */
  ],
  "unique_field_count": 2
}

我想将它反序列化为以下模型:

public class RootObject
{
    [JsonProperty("total_events")]
    public int TotalEvents { get; set; }

    [JsonProperty("json.appID")]
    public List<JsonAppID> AppIds { get; set; }

    [JsonProperty("unique_field_count")]
    public int UniqueFieldCount { get; set; }
}

public class JsonAppID
{
    [JsonProperty(PropertyName = "count")]
    public int Count { get; set; }

    [JsonProperty(PropertyName = "term")]
    public string Term { get; set; }
}

但是当我尝试时,我得到以下异常:

Newtonsoft.Json.JsonSerializationException:无法将当前JSON数组(例如[1,2,3])反序列化为类型“JsonAppID”,因为该类型需要JSON对象(例如{“name”:“value”})才能正确反序列化。 要修复此错误,请将JSON更改为JSON对象(例如{“name”:“value”})或将反序列化类型更改为数组或实现集合接口的类型(例如ICollection,IList),例如List从JSON数组反序列化。 JsonArrayAttribute也可以添加到类型中以强制它从JSON数组反序列化。 路径'['json.appID'] [2]',第12行,第6位。

如何忽略"json.appID"数组中不需要的空数组并成功反序列化我的模型?

答案

当预期的JSON值类型(对象,数组或基元)与观察到的类型不匹配时,Json.NET将抛出异常。在您的情况下,您的JsonAppID类型对应于JSON对象 - 一组无序的名称/值对,以{(左大括号)开头,以}(右大括号)结束。遇到数组时,会抛出您看到的异常。

如果您希望以静默方式跳过对象数组中的无效值类型,可以为custom JsonConverter引入ICollection<T>,它就是这样:

public class TolerantObjectCollectionConverter<TItem> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return !objectType.IsArray && objectType != typeof(string) && typeof(ICollection<TItem>).IsAssignableFrom(objectType);
    }

    public override bool CanWrite { get { return false; } }

    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)
    {
        // Get contract information
        var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonArrayContract;
        if (contract == null || contract.IsMultidimensionalArray || objectType.IsArray)
            throw new JsonSerializationException(string.Format("Invalid array contract for {0}", objectType));

        // Process the first token
        var tokenType = reader.SkipComments().TokenType;
        if (tokenType == JsonToken.Null)
            return null;
        if (tokenType != JsonToken.StartArray)
            throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));

        // Allocate the collection
        var collection = existingValue as ICollection<TItem> ?? (ICollection<TItem>)contract.DefaultCreator();

        // Process the collection items
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.EndArray:
                    return collection;

                case JsonToken.StartObject:
                case JsonToken.Null:
                    collection.Add(serializer.Deserialize<TItem>(reader));
                    break;

                default:
                    reader.Skip();
                    break;
            }
        }
        // Should not come here.
        throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
    }
}

public static partial class JsonExtensions
{
    public static JsonReader SkipComments(this JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment && reader.Read())
            ;
        return reader;
    }
}

然后将其应用于您的数据模型,如下所示:

public class JsonAppID
{
    [JsonProperty(PropertyName = "count")]
    public int Count { get; set; }

    [JsonProperty(PropertyName = "term")]
    public string Term { get; set; }
}

public class RootObject
{
    [JsonProperty("total_events")]
    public int TotalEvents { get; set; }

    [JsonProperty("json.appID")]
    [JsonConverter(typeof(TolerantObjectCollectionConverter<JsonAppID>))]
    public List<JsonAppID> AppIds { get; set; }

    [JsonProperty("unique_field_count")]
    public int UniqueFieldCount { get; set; }
}

样本工作.Net fiddle

以上是关于在反序列化时如何忽略JSON对象数组中的空白数组?的主要内容,如果未能解决你的问题,请参考以下文章

Newtonsoft.JSON 在反序列化数组中被双引号包围的对象时窒息

Gson 在反序列化对象时忽略 null

在 C# 中将 JSON 数组反序列化为对象

在 xml 序列化期间忽略属性,但在反序列化期间不忽略

如何忽略 JSON 响应中列表中的特定字段

如何反序列化 JSON 数组并忽略根节点?