【问题标题】:JSON.NET deserialize a specific propertyJSON.NET 反序列化特定属性
【发布时间】:2016-10-19 04:36:04
【问题描述】:

我有以下JSON 文字:

{
    "PropOne": {
        "Text": "Data"
    }
    "PropTwo": "Data2"
}    

我想将PropOne 反序列化为PropOneClass 类型,而不需要反序列化对象上的任何其他属性的开销。这可以使用 JSON.NET 完成吗?

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    JSON 不是太大,所以我会采纳 Matt Johnson 的建议并反序列化整个内容。感谢 jcwrequests 的回答,我能够使用这种方法:

    var jObject = JObject.Parse(json);
    var jToken = jObject.GetValue("PropTwo");
    PropTwoClass value = jToken.ToObject(typeof(PropTwoClass));
    

    【讨论】:

    • 这也可以:var propTwoClass = jToken.ToObject<PropTwoClass>();
    【解决方案2】:
    public T GetFirstInstance<T>(string propertyName, string json)
    {
        using (var stringReader = new StringReader(json))
        using (var jsonReader = new JsonTextReader(stringReader))
        {
            while (jsonReader.Read())
            {
                if (jsonReader.TokenType == JsonToken.PropertyName
                    && (string)jsonReader.Value == propertyName)
                {
                    jsonReader.Read();
    
                    var serializer = new JsonSerializer();
                    return serializer.Deserialize<T>(jsonReader);
                }
            }
            return default(T);
        }
    }
    
    public class MyType
    {
        public string Text { get; set; }
    }
    
    public void Test()
    {
        string json = "{ \"PropOne\": { \"Text\": \"Data\" }, \"PropTwo\": \"Data2\" }";
    
        MyType myType = GetFirstInstance<MyType>("PropOne", json);
    
        Debug.WriteLine(myType.Text);  // "Data"
    }
    

    这种方法避免了必须反序列化整个对象。但请注意,只有当 json 显着很大并且您要反序列化的属性在数据中相对较早时,这才会提高性能。否则,你应该反序列化整个事情并取出你想要的部分,比如 jcwrequests 回答节目。

    【讨论】:

    • 略微更新以获得更好的可重用性。
    • 这个方法被破坏了,它会在任何级别的任何地方捕获第一个属性“PropOne”,而不仅仅是在树的根部。它可以通过跟踪级别来修复,并且只在根级别接受正确的属性名称。
    • 请注意,如果您不确定要解码的 JSON 字符串是什么,这也很有用,并且您需要读取一个属性来弄清楚。
    【解决方案3】:

    Omar's answer 的一个更简单的解决方案是使用包装器。

    class Wrapper
    {
        public PropOneClass PropOne;
    }
    
    JsonConvert.Deserialize<Wrapper>(json).PropOne
    

    我的测试发现它快了大约 30%。

    【讨论】:

    • 这是一种更加灵活的方法。创建仅具有您要反序列化的属性的类,它会即时跳过所有批量,并且运行速度更快。
    【解决方案4】:
     var json = "{ "PropOne": { "Text": "Data" } "PropTwo": "Data2" }";
    
     JObject o = JObject.Parse(json);
     var val = o.PropTwo;
    

    使用 JSON Linq 提供程序,您无需将对象反序列化为已知类型。

    【讨论】:

      【解决方案5】:

      Matt's answer 是迄今为止最快的解决方案,尽管它有一个错误。 这是我解决这个问题的尝试。 此方法将仅返回根级别的匹配属性。 尽管对于有效的 JSON,它可能会起作用,但在计算开始和结束标记方面仍有一种幼稚的方法。

      马特,请随意将其复制到您的答案中。

      public T GetFirstInstance<T>(string propertyName, string json)
      {
          using (var stringReader = new StringReader(json))
          using (var jsonReader = new JsonTextReader(stringReader))
          {
              int level = 0;
      
              while (jsonReader.Read())
              {
                  switch (jsonReader.TokenType)
                  {
                      case JsonToken.PropertyName:
                          if (level != 1)
                              break;
                          if ((string)jsonReader.Value == propertyName)
                          {
                              jsonReader.Read();
      
                              return (T)jsonReader.Value; 
                          }
                          break;
      
                      case JsonToken.StartArray:
                      case JsonToken.StartConstructor:
                      case JsonToken.StartObject:
                          level++;
                          break;
      
                      case JsonToken.EndArray:
                      case JsonToken.EndConstructor:
                      case JsonToken.EndObject:
                          level--;
                          break;
                  }
      
              }
              return default(T);
          }
      }
      

      【讨论】:

      • 如何跳过令牌的孩子,这样我们只得到根级节点:while (jsonReader.Read()) { if ((string)jsonReader.Value == propertyName) { //return } jsonReader.Skip(); }
      • @amolbk yes Skip 看起来像是添加了 6 months ago 并且会简化代码。也许这对于一个新的答案更好。
      【解决方案6】:

      使用JsonIgnore - 这将导致 Json.Net 完全忽略该属性,无论是用于序列化还是反序列化。

      另外,请查看link

      【讨论】:

      • 我没有包含PropOnePropTwo 的复合对象,而是有两个单独的类分别代表PropOnePropTwo
      • 你也在序列化对象吗?
      • 如果你的意思是我是创建 JSON 的人,那么不,我得到的 JSON 是由第 3 方发送的。
      • NomadTraveler,您知道是否可以仅将 JsonIgnore 用于反序列化?
      最近更新 更多