【问题标题】:Skip json elements deserialization on condition在条件下跳过 json 元素反序列化
【发布时间】:2015-02-25 17:51:45
【问题描述】:

有以下问题。我需要将一堆相当大的 json 对象作为对象。但是有一些条件,当我实际上不需要其中一些时,例如,如果内部字段之一是“isDeleted:true”。现在我必须首先自动通过 JsonConvert.DeserializeObject<..>(stringJson) 所有数据数组,然后在必要的过滤器中进行选择。我想要实现的是在条件不正确时跳过一些整个元素。除了手动转换,还有什么方法可以实现吗?

更新: json 看起来像这样:

{
  results:[
     around 20 fields here with inner objects,
     isDeleted:"true",
     user:{
        another dozen of fields
     },
     images:[{..},{..}]
 ]}

【问题讨论】:

  • 你的 JSON 是什么样的?
  • 在序列化时是可以的,因为手动修改创建的json字符串比较困难,反序列化时很简单。检查您的条件并为某些属性分配默认值。顺便说一句:你为​​什么要这样做。您期望获得一些性能提升吗?
  • EZI,是的,我真的很想获得一些性能并减少操作,因为它是一个移动应用程序。你说它简单是什么意思?手动反序列化?我同意这并不难,它只是手动填充我想要避免的每个字段和内部对象。

标签: c# json serialization windows-runtime json.net


【解决方案1】:

根据文档,JsonReader

表示提供对序列化 JSON 数据的快速、非缓存、仅向前访问的读取器。

因此,为了在反序列化集合时跳过已删除的项目,您需要将每个集合条目的 JSON 读取到内存中以某种方式检查isDeleted 属性。如果您的集合项目类太重以至于您不想在非绝对需要时创建一个,您可以使用自定义 JsonConverter 将每个条目加载到 JObject 容器中,然后检查 isDeleted:

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

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var list = (existingValue as List<T>);
        if (list == null)
            list = new List<T>();
        if (reader.TokenType != JsonToken.StartArray)
            return list;
        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndArray)
                break;
            var obj = JObject.Load(reader);
            var deleted = obj["isDeleted"];
            if (deleted != null)
            {
                if (deleted.Type == JTokenType.Boolean && (bool)deleted)
                    continue;
            }
            if (obj != null)
            {
                list.Add((T)obj.ToObject<T>(serializer));
            }
        }
        return list;
    }

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

然后将其应用于您要过滤的任何 List&lt;T&gt; 属性:

[DataContract]
public class RootObject
{
    public RootObject()
    {
        this.ResultList = new List<Item>();
    }

    [DataMember(Name="results")]
    [JsonConverter(typeof(DeletetedItemSkippingCollectionConverter<Item>))]
    public List<Item> ResultList { get; set; }
}

或者,您可以将集合中的每个项目加载到其“最终”表示中,检查它是否被删除,如果是,则将其丢弃。假设你的对象都实现了一个接口IsDeleted,你可以这样做:

public interface IIsDeleted
{
    bool IsDeleted { get; }  // Corresponds it "isDeleted" property in the JSON.
}

public class IsDeletetedItemSkippingCollectionConverter<T> : JsonConverter where T : IIsDeleted
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<T>);
    }

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var list = (existingValue as List<T>);
        if (list == null)
            list = new List<T>();
        if (reader.TokenType != JsonToken.StartArray)
            return list;
        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndArray)
                break;
            var obj = serializer.Deserialize<T>(reader);
            if (obj == null || obj.IsDeleted)
            {
                var disposable = obj as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
                continue;
            }
            list.Add(obj);
        }
        return list;
    }

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

【讨论】:

  • a) 许多JObject.Loads 来检查isDeleted,这会更高效吗? b) isDeleted 可能是最后一个属性,因此这种方法可能会导致错误的结果。
  • @EZI - 发帖人需要测试性能。由于他/她的类包含图像,因此加载到中间表示可能比实际在非托管内存中创建图像更好。但请参阅我刚刚添加的替代方案。
  • @EZI - 错误的结果怎么可能?
  • a) 虽然 OP 对性能感兴趣,但您说 “我可以发布任何答案,OP 应该检查一下”。至少说几句话,说明为什么这可能会更好 b) 没有这样的东西(使用 Json.Net)可以直接反序列化为图像 c) 我也是懒得准备代码只是为了显示某人的答案不正确。
  • 感谢您的建议,但我认为这并不能解决任何问题,因为我仍然需要解析所有数组项以检查属性。我认为这可能是一种在不反序列化其他属性的情况下进行检查的方法,但据我所知——读者只能前进,所以我无法在根目录中搜索它来检查然后决定是否转到下一个数组元素或解析整个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多