问题描述
我有以下 JSON 字符串:
I have the following JSON string:
{
"values": {
"details": {
"property1": "94",
"property2": "47",
"property3": "32",
"property4": 1
},
count: 4
}
}
我将把它映射到以下模型:
I am going to map this to the following model:
public class Details
{
public string property1 { get; set; }
public string property2 { get; set; }
public string property3 { get; set; }
public int property4 { get; set; }
}
public class Values
{
public Details details { get; set; }
public int count { get; set; }
}
public class RootObject
{
public Values values { get; set; }
}
当像这样反序列化这个 JSON 字符串时,我希望能够在运行时将这些属性名称映射到不同的名称:
I want to be able to map the these property names to different names at runtime when deserializing this JSON string like this:
JsonConvert.DeserializeObject<RootObject>(jsonString);
例如,在反序列化过程中,我希望将property1"的名称反序列化为differen_property_name1"或differen_property_name2"或differen_property_name3".因为我在运行时选择了新名称(我会将property1"名称更改为的新名称),所以我无法使用使用 JsonPropertyAttribute 的解决方案,如下所示:
For example, in the deserialization process, I want the deserialize the name of "property1" to "differen_property_name1" or "differen_property_name2" or "differen_property_name3". Because I am choosing the new name at runtime (the new name to which I will change the "property1" name to), I can't use the solution using JsonPropertyAttribute, as suggested here:
.NET NewtonSoft JSON 反序列化映射到不同的属性名称
上述问题的一个答案(Jack 的答案)使用 DefaultContractResolver 的继承,但在这种情况下似乎不起作用.
One of the answers of the above question (Jack's answer) uses inheritance of DefaultContractResolver but it doesn't seem to work in that case.
更新
稍后,我需要序列化从反序列化中获得的对象,并将属性映射到不同的属性名称,在运行时定义.我使用了与 Brian 建议的相同方法进行序列化:
Later on, I needed to serialize the object I got from the deserialization and map the properties to different property names, defined at runtime. I used the same method as Brian proposed to do the serialization:
我使用字典来映射我的新属性名称:
I used the dictionary to map my new property names:
var map = new Dictionary<Type, Dictionary<string, string>>
{
{
typeof(Details),
new Dictionary<string, string>
{
{"property1", "myNewPropertyName1"},
{"property2", "myNewPropertyName2"},
{"property3", "myNewPropertyName3"},
{"property4", "myNewPropertyName4"}
}
}
};
然后我使用 Brian 的 DynamicMappingResolver 像这样序列化对象:
and then I used Brian's DynamicMappingResolver to serialize the object like this:
var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicMappingResolver(map)
};
var root = JsonConvert.SerializeObject(myObjectInstance, settings);
推荐答案
您可以使用自定义 ContractResolver
来执行此操作.基本上,这与将 [JsonProperty]
属性放在要映射到不同 JSON 属性名称的每个类成员上的想法相同,除非您通过解析器以编程方式执行此操作.在反序列化之前设置解析器时,您可以将所需映射的字典传递给解析器.
You could use a custom ContractResolver
to do this. Basically it is the same idea as putting a [JsonProperty]
attribute on each class member for which you want to map to a different JSON property name, except you do it programmatically via the resolver. You can pass a dictionary of your desired mappings to the resolver when setting it up just before deserializing.
自定义解析器代码如下所示:
Here is what the custom resolver code might look like:
class DynamicMappingResolver : DefaultContractResolver
{
private Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap;
public DynamicMappingResolver(Dictionary<Type, Dictionary<string, string>> memberNameToJsonNameMap)
{
this.memberNameToJsonNameMap = memberNameToJsonNameMap;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
Dictionary<string, string> dict;
string jsonName;
if (memberNameToJsonNameMap.TryGetValue(member.DeclaringType, out dict) &&
dict.TryGetValue(member.Name, out jsonName))
{
prop.PropertyName = jsonName;
}
return prop;
}
}
要使用解析器,首先构造一个 Dictionary<Type, Dictionary<string, string>>
包含您的映射.外部字典的键是要映射其属性的类类型;内部字典是类属性名称到 JSON 属性名称的映射.您只需为名称尚未与 JSON 匹配的属性提供映射.
To use the resolver, first construct a Dictionary<Type, Dictionary<string, string>>
containing your mappings. The outer dictionary's key is the the class type(s) whose properties you want to map; the inner dictionary is a mapping of the class property names to JSON property names. You only need to provide a mapping for the properties whose names don't already match the JSON.
因此,例如,如果您的 JSON 看起来像这样(注意 details
对象内属性的名称已更改)...
So, for example, if your JSON looked like this (notice the changed names of the properties inside the details
object)...
{
"values": {
"details": {
"foo": "94",
"bar": "47",
"baz": "32",
"quux": 1
},
count: 4
}
}
...如果您想将其映射到问题中的类,您可以像这样创建字典:
...and you wanted to map it to the classes in your question, you would create the dictionary like this:
var map = new Dictionary<Type, Dictionary<string, string>>
{
{
typeof(Details),
new Dictionary<string, string>
{
{"property1", "foo"},
{"property2", "bar"},
{"property3", "baz"},
{"property4", "quux"}
}
}
};
最后一步是使用新的解析器实例设置序列化器设置,为其提供刚刚构建的映射字典,然后将设置传递给 JsonConvert.DeserializeObject()
.
The last step is to set up the serializer settings with a new resolver instance, giving it the mapping dictionary you just constructed, and then pass the settings to JsonConvert.DeserializeObject()
.
var settings = new JsonSerializerSettings
{
ContractResolver = new DynamicMappingResolver(map)
};
var root = JsonConvert.DeserializeObject<RootObject>(json, settings);
这是一个演示:https://dotnetfiddle.net/ULkB0J
这篇关于Json.NET 反序列化或序列化 json 字符串并将属性映射到运行时定义的不同属性名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!