2017-02-11 4 views
1

Я пытаюсь использовать JsonConvert.DeserializeObject (string), чтобы десериализовать строку в jobject, который может использовать динамический доступ к json-документу на лету. Однако я хочу, чтобы избежать, зная корпус документа, так что я могу ввестиjson.net custom deserialization 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 чувствителен к регистру и не предоставляет конструктор использовать случай-инвариантной компаратор в своем JPropertyKeyedCollection. И JObjectDynamicProxy.TryGetMember(), кажется, делает простой поиск, а не без учета регистра.

Таким образом, если вы не можете получить this answer работать, если вам нужен регистронезависимый динамический объект, вы можете взять один из заменителей ExpandoObject из How 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

Смежные вопросы