2017-02-11 121 views
1

我試圖使用JsonConvert.DeserializeObject(字符串)來反序列化一個字符串到一個jobject,可以使用動態訪問json文件。不過,我想避免知道文件的外殼,所以我可以鍵入json.net自定義jobject反序列化

dynamic document = JsonConvert.DeserializeObject(someString); 
Console.WriteLine(document.some.path.here.name); 

,並有它{"Some":{"path":{"HERE":{"Name":"test"}}} 工作,我不能找出如何創建一個自定義類json.net,將做到這一點對我基本上刪除工作對象的大小寫敏感(或者可能將所有屬性轉換爲小寫)

+1

你可以嘗試這樣的事情:http://stackoverflow.com/questions/9247478/pascal-case-dynamic-properties-with-json-net –

回答

1

要遞歸地將所有性質的JToken層次較低的情況下,你可以使用下面的擴展方法:

public static class JsonExtensions 
{ 
    public static TJToken RenamePropertiesToLowerInvariant<TJToken>(this TJToken root) where TJToken : JToken 
    { 
     return root.RenameProperties(s => s.ToLowerInvariant()); 
    } 

    public static TJToken RenameProperties<TJToken>(this TJToken root, Func<string, string> map) where TJToken : JToken 
    { 
     if (map == null) 
      throw new ArgumentNullException(); 
     if (root == null) 
      return null; 
     if (root is JProperty) 
     { 
      return RenameReplaceProperty(root as JProperty, map, -1) as TJToken; 
     } 
     else 
     { 
      foreach (IList<JToken> obj in root.DescendantsAndSelf().OfType<JObject>()) 
       for (int i = obj.Count - 1; i >= 0; i--) 
        RenameReplaceProperty((JProperty)obj[i], map, i); 
      return root; 
     } 
    } 

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken node) 
    { 
     if (node == null) 
      return Enumerable.Empty<JToken>(); 
     var container = node as JContainer; 
     if (container != null) 
      return container.DescendantsAndSelf(); 
     else 
      return new[] { node }; 
    } 

    private static JProperty RenameReplaceProperty(JProperty property, Func<string, string> map, int index) 
    { 
     // JProperty.Name is read only so it will need to be replaced in its parent. 
     if (property == null) 
      return null; 
     var newName = map(property.Name); 
     if (newName == property.Name) 
      return property; 
     var value = property.Value; 
     // Setting property.Value to null on the old property prevents the child JToken hierarchy from getting recursively cloned when added to the new JProperty 
     // See https://github.com/JamesNK/Newtonsoft.Json/issues/633#issuecomment-133358110 
     property.Value = null; 
     var newProperty = new JProperty(newName, value); 
     IList<JToken> container = property.Parent; 
     if (container != null) 
     { 
      if (index < 0) 
       index = container.IndexOf(property); 
      container[index] = newProperty; 
     } 
     return newProperty; 
    } 
} 

然後做

dynamic document = JsonConvert.DeserializeObject<JToken>(someString).RenamePropertiesToLowerInvariant(); 

然而,JObject是大小寫敏感的,沒有提供任何構造函數來使用的情況下,不變的比較器在其JPropertyKeyedCollectionJObjectDynamicProxy.TryGetMember()似乎在做一個簡單的查找,而不是一個不區分大小寫的搜索。

所以,除非你能得到this answer工作,如果你需要一個不區分大小寫的動態對象,你可以採取替代之一ExpandoObjectHow to set ExpandoObject's dictionary as case insensitive?然後創建您自己的版本的ExpandoObjectConverter反序列化您替代的expando類型。

+0

恐怕jobject和我自己的expando對象之間的性能差異,但似乎是根據此q中提供的所有鏈接接受的路線 –

0

首先,確保您已下載最新版本的Json.NET(http://ud.ht/OrbT)。然後使用下面的代碼,因爲最新版本允許你這樣做,如以下幾點:

var str = {"Some":{"path":{"HERE":{"Name":"test"}}}; 
dynamic document = JObject.Parse(str); 
Console.WriteLine(document.Some.path.HERE.Name); 
+0

不知何故,它不適合我,它必須匹配JSON套管,document.some是空引用 –

+0

你確定嗎?它在Json.NET 6.0中不起作用 - 請參閱https://dotnetfiddle.net/2ooj6b。和['JObjectDynamicProxy.TryGetMember()'](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JObject.cs#L807)從那時起就沒有變化,區分大小寫的匹配。我也無法在[發行說明](https://github.com/JamesNK/Newtonsoft.Json/releases)中找到任何相關內容。 – dbc

+0

我的朋友,你的變量名是區分大小寫的。試試這個: 使用這個: Console.WriteLine(document.Some.path.HERE.Name); http://ud.ht/Gzwx – AHBagheri