json.net自定义Jobject反序列化 [英] json.net custom jobject deserialization
问题描述
我正在尝试使用JsonConvert.DeserializeObject(string)将字符串反序列化为Jobject,该Jobject可以与dynamic一起动态访问json文档.但是我想避免知道文档的大小写,所以我可以键入
I'm trying to use JsonConvert.DeserializeObject(string) to deserialize a string into an jobject that can use with dynamic to access the json document on the fly. However I want to avoid knowing the casing of the document so I can type
dynamic document = JsonConvert.DeserializeObject(someString);
Console.WriteLine(document.some.path.here.name);
并使其在{"Some":{"path":{"HERE":{"Name":"test"}}}
上运行
我找不到如何为自己创建json.net的自定义类的方法,基本上可以删除jobject上的区分大小写(或者可以将所有属性转换为小写)
and have it work on {"Some":{"path":{"HERE":{"Name":"test"}}}
I can't find out how to create a custom class for json.net that will do that for me, basically removing case sensitivity on the jobject (or maybe transform all properties to lower case)
推荐答案
要将JToken
层次结构中的所有属性递归转换为小写,可以使用以下扩展方法:
To recursively convert all properties in a JToken
hierarchy to lower case, you can use the following extension method:
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
区分大小写,并且没有提供构造函数在其 JObjectDynamicProxy.TryGetMember()
似乎是在进行简单查找,而不区分大小写.
However, JObject
is case sensitive and provides no constructor to use a case-invariant comparer in its JPropertyKeyedCollection
. And JObjectDynamicProxy.TryGetMember()
seems to be doing a simple lookup not a case-insensitive search.
因此,除非您能够获得此答案起作用,否则,如果您需要不区分大小写的动态对象,则可以从>如何将ExpandoObject的字典设置为不区分大小写?然后创建您自己的 ExpandoObjectConverter
反序列化您的替代expando类型.
So, unless you can get this answer to work, if you need a case-insensitive dynamic object, you could take one of the replacements for ExpandoObject
from How to set ExpandoObject's dictionary as case insensitive? then create your own version of ExpandoObjectConverter
to deserialize your alternative expando type.
这篇关于json.net自定义Jobject反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!