Json.NET将json字符串和映射属性反序列化或序列化为运行时定义的不同属性名称

我有以下JSON字符串:

{ "values": { "details": { "property1": "94", "property2": "47", "property3": "32", "property4": 1 }, count: 4 } } 

我将把它映射到以下模型:

 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字符串,如下所示:

 JsonConvert.DeserializeObject(jsonString); 

例如,在反序列化过程中,我希望将“property1”的名称反序列化为“differen_property_name1”或“differen_property_name2”或“differen_property_name3”。 因为我在运行时选择新名称 (我要将“property1”名称更改为的新名称),我不能使用JsonPropertyAttribute的解决方案,如下所示:

.NET NewtonSoft JSON将映射反序列化为不同的属性名称

上述问题的答案之一(杰克的回答)使用了DefaultContractResolver的inheritance,但在这种情况下它似乎不起作用。

更新

稍后,我需要序列化从反序列化中获得的对象,并将属性映射到在运行时定义的不同属性名称。 我使用了与Brian提出的相同的方法来进行序列化:

我用字典来映射我的新属性名称:

 var map = new Dictionary<Type, Dictionary> { { typeof(Details), new Dictionary { {"property1", "myNewPropertyName1"}, {"property2", "myNewPropertyName2"}, {"property3", "myNewPropertyName3"}, {"property4", "myNewPropertyName4"} } } }; 

然后我使用Brian的DynamicMappingResolver来序列化对象,如下所示:

 var settings = new JsonSerializerSettings { ContractResolver = new DynamicMappingResolver(map) }; var root = JsonConvert.SerializeObject(myObjectInstance, settings); 

您可以使用自定义ContractResolver来执行此操作。 基本上它与将[JsonProperty]属性放在要映射到不同JSON属性名称的每个类成员上的想法相同,除非您通过解析程序以编程方式执行此操作。 在反序列化之前进行设置时,可以将所需映射的字典传递给解析器。

以下是自定义解析程序代码的外观:

 class DynamicMappingResolver : DefaultContractResolver { private Dictionary> memberNameToJsonNameMap; public DynamicMappingResolver(Dictionary> memberNameToJsonNameMap) { this.memberNameToJsonNameMap = memberNameToJsonNameMap; } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty prop = base.CreateProperty(member, memberSerialization); Dictionary dict; string jsonName; if (memberNameToJsonNameMap.TryGetValue(member.DeclaringType, out dict) && dict.TryGetValue(member.Name, out jsonName)) { prop.PropertyName = jsonName; } return prop; } } 

要使用解析器,首先构造一个包含映射的Dictionary> 。 外部字典的键是要映射其属性的类类型; 内部字典是类属性名称到JSON属性名称的映射。 您只需要为名称与JSON不匹配的属性提供映射。

因此,例如,如果您的JSON看起来像这样(请注意details对象中属性的更改名称)…

 { "values": { "details": { "foo": "94", "bar": "47", "baz": "32", "quux": 1 }, count: 4 } } 

…并且您想将它映射到问题中的类,您可以像这样创建字典:

 var map = new Dictionary> { { typeof(Details), new Dictionary { {"property1", "foo"}, {"property2", "bar"}, {"property3", "baz"}, {"property4", "quux"} } } }; 

最后一步是使用新的解析器实例设置序列化程序设置,为其提供刚构建的映射字典,然后将设置传递给JsonConvert.DeserializeObject()

 var settings = new JsonSerializerSettings { ContractResolver = new DynamicMappingResolver(map) }; var root = JsonConvert.DeserializeObject(json, settings); 

这是一个演示: https : //dotnetfiddle.net/ULkB0J

为什么一步到位呢? 为什么不反序列化到标准对象中,然后使用Automapper动态映射它们?

就像是:

 Mapper.Initialize(c => { c.ReplaceMemberName("property1 ", "differen_property_name1"); }); 

如果您不想使用自定义ContractResolver执行此操作。 使用[JsonProperty("")]查找属性名称的不同变体,并返回另一个属性,如下所示:

 public class Details { private string _property1; private string _property2; [JsonProperty("property1")] public string prop1 {get;set;} [JsonProperty("foo")] public string foo {get;set;} public string getProperty1 { get {_property1=prop1??foo;return _property1;} set{prop1=value;foo=value;} } [JsonProperty("property2")] public string prop2 {get;set;} [JsonProperty("bar")] public string bar {get;set;} public string getProperty2 { get {_property2=prop2??bar;return _property2;} set {prop2=value;bar=value;} } } 

在这里演示: https : //dotnetfiddle.net/V17igc

我不相信JSON.net对你想要的东西有任何支持。 如果您不知道格式,则应该将JSON反序列化为JObject如果您知道格式,则应将其反序列化为通用格式(例如,如果JSON始终表示property1 ,则可以使用通用对象来表示它)。

获得通用对象后,接下来需要翻译字段。 任何不可更改的都可以直接完成,但对于其他任何事情,您都需要使用Reflection。

基本上它涉及获取类型( typeof(Details)obj.GetType() ),然后搜索要更新的Property。 最后,您应该能够找到setter方法并调用它从您的通用对象中提供原始值。