【问题标题】:I need Newtonsoft JSON deserialization to skip an entry in a given dictionary JSON我需要 Newtonsoft JSON 反序列化来跳过给定字典 JSON 中的条目
【发布时间】:2020-03-08 20:50:01
【问题描述】:

我有这个类作为我的 JSON 模式(这个词对吗?):

class BasicInfoDatabase : Dictionary<string, BasicInfo>,
    IDictionary<string, BasicInfo>, 
    ICollection<KeyValuePair<string, BasicInfo>>, 
    IDictionary, 
    ICollection,
    IReadOnlyDictionary<string, BasicInfo>, 
    IReadOnlyCollection<KeyValuePair<string, BasicInfo>>,
    IEnumerable<KeyValuePair<string, BasicInfo>>, 
    IEnumerable, 
    ISerializable, 
    IDeserializationCallback 
{ }

注意:这里指定了Dictionary 的所有接口,以解决不相关的错误。否则,我会省略它们。

输入 JSON 字符串中有一个未格式化为 BasicInfo 对象的条目。在反序列化输入字符串时,我想忽略该特定条目。这是我用于此用途的代码:

private static bool HandleInfoReceipt( string jsonStr, out BasicInfoDatabase infoDb ) {
    infoDb = new BasicInfoDatabase();

    JObject respJson = JObject.Parse( jsonStr );
    if( respJson.Count == 0 ) {
        return false;
    }

    infoDb = respJson.ToObject<BasicInfoDatabase>();
    if( infoDb == null ) {
        throw new NullReferenceException( "No info found" );
    }

    return true;
}

如何跳过该条目?

【问题讨论】:

标签: c# json dictionary json.net deserialization


【解决方案1】:

JObject 中过滤出属性非常简单。如何做到这一点取决于您对 JSON 的了解和不了解的情况。

例如,假设您的 BasicInfo 类是这样定义的:

class BasicInfo
{ 
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Amount { get; set; }
}

你的 JSON 看起来像这样:

{
  "good": {
    "Id": 1,
    "Name": "Foo",
    "Amount": 14.95
  },
  "acceptable": {
    "Id": 2,
    "Name": "Bar"
  },
  "suspect": {
    "Id": 3,
    "Hmm": "Blah"
  },
  "bad": {
    "Foo": "Bar",
    "Baz": "Quux"
  },
  "ugly": "total garbage"
}

如果您知道导致问题的特定键,您可以制作一个简单的扩展方法来过滤掉它们,如下所示:

public static void FilterOutUnwantedProperties(this JObject jo, params string[] keys)
{
    var unwantedProperties = jo.Properties().Where(jp => keys.Contains(jp.Name)).ToList();

    foreach (JProperty prop in unwantedProperties)
    {
        prop.Remove();
    }
}

然后,从您的 HandleInfoReceipt 方法中调用它,如下所示:

respJson.FilterOutUnwantedProperties("bad", "ugly");

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


另一方面,也许您不提前知道密钥,或者它们是动态的。也许更好的方法是让扩展方法检查 JObject 中的每个属性值实际上是一个对象本身,并检查 child 对象属性的名称以确保它们中的至少一个(或所有其中?)匹配您想要的项目类型。这可能看起来像这样:

public static void FilterOutPropertiesThatAreNotCompatibleWith<TItem>(this JObject jo, BindingFlags flags=BindingFlags.Public|BindingFlags.Instance)
{
    var knownItemPropertyNames = 
        typeof(TItem).GetProperties(flags)
                     .Select(p => p.Name);
    var knownItemFieldNames = 
        typeof(TItem).GetFields(flags)
                     .Select(p => p.Name);
    var knownItemMemberNames = new HashSet<string>(knownItemPropertyNames);
    knownItemMemberNames.UnionWith(knownItemFieldNames);

    var unwantedProperties = 
        jo.Properties()
          .Where(jp => jp.Value.Type != JTokenType.Object ||
                       !jp.Value.Children<JProperty>()
                                .Any(cp => knownItemMemberNames.Contains(cp.Name)))
          .ToList();

    foreach (JProperty prop in unwantedProperties)
    {
        prop.Remove();
    }
}

你可以这样称呼这个版本:

respJson.FilterOutPropertiesThatAreNotCompatibleWith<BasicInfo>();

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

【讨论】:

    【解决方案2】:

    可能是这样的:

     var result = new BasicInfoDatabase();
     var jObject = JObject.Parse( jsonStr );
     foreach (var kvp in jObject )
     {
         if(kvp.Key != "<property-you-want-to-skip>")
         {
             result.Add(kvp.Key, kvp.Value.ToObject<BasicInfo>());
         }  
     }
    

    编辑

    更多这样的:

    kvp.Value.ToObject<BasicInfo>();
    

    【讨论】:

    • 你的意思是cs result.Add(kvp.Key, JsonConvert.DeserializeObject&lt;BasicInfo&gt;(kvp.Value.ToString())); 吗?
    猜你喜欢
    • 2013-06-06
    • 1970-01-01
    • 2020-09-06
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多