Newtonsoft JsonConvert.DeserializeObject如何忽略空对象

时间:2017-08-08 15:41:44

标签: c# json.net

我有以下类定义:

public class Tag
{
    public Guid? TagId { get; set; }
    public string TagText { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class Wiki
{
    public Guid? WikiId { get; set; }
    public string WikiText { get; set; }
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
}

从数据库中我得到以下json对象:

{
    "WikiId": "83981284-0AD3-4420-90AB-15E3BF6BD7B7",
    "WikiText": "Text",
    "Title": "Title",
    "CreatedOn": "2017-08-07T09:16:06.0800000",
    "Tags": [{}] // <-- here i would like to ignore the empty Tag object
}

当我现在做JsonConvert.DeserializeObject<Wiki>(json)时,我得到一个带有1个Tag的列表的Wiki对象,其值为TagId: null, TagText: null and CreatedOn: "0001-01-01T00:00:00"

在反序列化时有没有办法忽略空Tag对象?我尝试了几个JsonSerializerSettings,但没有任何帮助。

3 个答案:

答案 0 :(得分:4)

您可以使用自定义JsonConverter在反序列化期间忽略空对象。这样的事情可以奏效:

class IgnoreEmptyItemsConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(List<T>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        List<T> list = new List<T>();
        JArray array = JArray.Load(reader);
        foreach (JObject obj in array.Children<JObject>())
        {
            if (obj.HasValues)
            {
                list.Add(obj.ToObject<T>(serializer));
            }
        }
        return list;
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用转换器,只需在[JsonConverter]属性中添加Tags属性,如下所示:

public class Wiki
{
    ...
    [JsonConverter(typeof(IgnoreEmptyItemsConverter<Tag>))]
    public IEnumerable<Tag> Tags { get; set; }
}

小提琴:https://dotnetfiddle.net/hrAFsh

答案 1 :(得分:2)

您必须在转换后检测空标记对象并自行删除它们。从反序列化程序的角度来看,{}是一个完全有效且完整的Tag对象,其属性都未设置。

以下内容应该有效(假设C#6):

Wiki wiki = JsonConvert.DeserializeObject<Wiki>(json);
wiki.Tags = Wiki.Tags?.Where(x => x.TagId.HasValue)?.ToList();

答案 2 :(得分:1)

由于@ Brian-Rogers的出色回答,我得以提出一种非通用解决方案,该解决方案适用于所有馆藏,而不仅仅是List

public class IgnoreEmptyArrayItemsConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        bool result = typeof(System.Collections.IEnumerable).IsAssignableFrom(objectType);
        return result;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var tokenIndexesToRemove = new List<int>();

        var array = JArray.Load(reader);

        for (int i = 0; i < array.Count; i++)
        {
            var obj = array[i];
            if (!obj.HasValues)
                tokenIndexesToRemove.Add(i);
        }

        foreach (int index in tokenIndexesToRemove)
            array.RemoveAt(index);

        var result = array.ToObject(objectType, serializer);
        return result;
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

此解决方案不会循环遍历对象,反序列化它们并将它们逐个添加到硬编码的List集合中,而是会从JArray删除有问题的令牌并让库将整个数组反序列化为应有的类型

用法:

public class Wiki
{
    ...
    [JsonConverter(typeof(IgnoreEmptyItemsConverter))] // No generic parameter needed
    public HashSet<Tag> Tags { get; set; }
}

提琴:https://dotnetfiddle.net/9FCcpD