【问题标题】:How to get all not exist keys after JsonConvert DeserializeObject in Json.Net?如何在 Json.Net 中的 JsonConvert DeserializeObject 之后获取所有不存在的键?
【发布时间】:2021-12-29 14:03:03
【问题描述】:

您好,我正在使用 NewtonSoft Json.Net 反序列化我的 json 数据。我通常反序列化 json 字符串,但我想检查所有不存在的键。

例如这里是一个json数据。

{
    "Hp": 100,
    "PlayerInfo": {
        "Atk": 10,
        "Def": 20
    },
    "Mp": 100
} 

而且我有一个可以匹配上述数据的结构。

[Serializable]
public struct CharaData
{
    public int Hp;
    
    [Serializable]
    public struct PlayerInfoData
    {
       public int Atk;
       public int Def;
       public int Spd; 
    }
    PlayerInfoData PlayerInfo;
}
 

我会像这样对它进行去色化。

JsonConvert.DeserializeObject<CharaData>(jsonStr);
  • json 数据中有 Mp 键,但结构中没有。

  • PlayerInfoData 中,json 数据中没有Spd 键,但在结构中有一个Spd 字段。

    • 嗯... Spd 字段似乎初始化为默认值 0,它可能是一个错误。

所以我想检查哪些键不在结构中。 以及哪些结构字段因为不存在而没有反序列化。

我会尽我所能防止这些发生,但是如果在从json数据反序列化的过程中缺少某些键,我会登录查找为什么没有反序列化的问题 完全成功。

[Error][CharaData::Mp key not exist in json string]
[Error][CharaData::PlayerInfo::Spd field not exist in struct]

似乎在 JsonConvert 类中没有任何方法可以检查它。 我看到了

[JsonProperty(Required = Required.Always)] 

但这不会检查所有的键。 这个需要写自定义的json转换器吗?

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    使用此代码

    var result= JsonConvert.DeserializeObject<CharaData>(jsonStr);
    
    var mp=result.Mp;
    var playerInfo=result.PlayerInfo;
    

    如果您想知道存在哪些键,只需检查它们是否为空。默认情况下,所有键都是空的。如果它们不为空,则表示它们从 json 中获取值。例如,您可以使用此代码

    if (mp==null) Console.WriteLine ("mp is not exist in json");
    

    另一种方法是使用反射检查所有属性

        var props = result.GetType().GetProperties();
        var nulls = new List<string>();
    
        foreach (var prop in props)
        {
            var propInstance = prop.GetValue(result, null);
    
            if (propInstance == null) nulls.Add(prop.Name);
    
            if (prop.Name == "PlayerInfo")
            {
                var prps = prop.PropertyType.GetProperties();
                foreach (var prp in prps)
                    if (prp.GetValue(propInstance, null) == null) nulls.Add(prop.Name+"."+prp.Name);
            }
    
        }
        foreach (var n in nulls)
            Console.WriteLine(n + " doesn't have value");
    

    测试结果

    PlayerInfo.Spd doesn't have value
    

    public class PlayerInfo
        {
            public int? Atk { get; set; }
            public int? Def { get; set; }
            public int? Spd { get; set; } 
        }
    
        public class CharaData
        {
            public int? Hp { get; set; }
            public PlayerInfo PlayerInfo { get; set; }
            public int? Mp { get; set; }
        }
    

    【讨论】:

      【解决方案2】:

      你的问题是双重的:

      1. 查找缺失的字段
      2. 查找额外字段

      在深入了解细节之前,让我们将CharaData 分为两个类

      [Serializable]
      public class CharaData
      {
          public int Hp;
          public PlayerInfoData PlayerInfo;
      }
      
      [Serializable]
      public class PlayerInfoData
      {
          public int Atk;
          public int Def;
          public int Spd;
      }
      

      缺少字段

      此解决方案依赖于JsonSchema

      private static Lazy<JSchema> schema = new Lazy<JSchema>(() => {
          var generator = new JSchemaGenerator();
          return generator.Generate(typeof(CharaData));
      }, true);
      
      public static void ReportMissingFields(string json)
      {
          var semiParsed = JObject.Parse(json);
                  
          try
          {
              semiParsed.Validate(schema.Value);
          }
          catch (JSchemaValidationException ex)
          {
              Console.WriteLine(ex.ValidationError.Message);
          }
      }
      
      • schema 以惰性方式存储 CharaData 的 json 架构
      • Validatejson 与架构进行比较,如果不匹配,则抛出 JSchemaValidationException
        • 它公开了一个类型为ValidationError 的属性,其中包含大量有关不匹配的信息

      额外字段

      此解决方案依赖于JsonExtensionDataAttribute

      [Serializable]
      internal class CharaDataExtras: CharaData
      {
          [JsonExtensionData]
          public IDictionary<string, JToken> ExtraFields;
      }
      
      ...
      
      public static void ReportExtraFields(string json)
      {
          var result = JsonConvert.DeserializeObject<CharaDataExtras>(json);
          foreach (var field in result.ExtraFields)
          {
              Console.WriteLine($"An extra field has found, called {field.Key}");
          }
      }
      
      • 我已将CharaData 定义为能够从中派生的类CharaDataExtras
      • 每个额外的字段都将被放入ExtraFields 字典中

      用法

      var json = File.ReadAllText("sample.json");
      ReportMissingFields(json);
      ReportExtraFields(json);
      

      输出:

      Required properties are missing from object: Spd.
      An extra field has found, called Mp
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-24
        • 1970-01-01
        • 1970-01-01
        • 2013-12-13
        • 1970-01-01
        相关资源
        最近更新 更多