2017-02-11 143 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