基于JsonSerializerSettings确定JSON.Net属性映射的技术问询
好的,我来帮你拆解JSON.Net中这两个核心的属性映射问题,结合特性、配置的优先级和规则一步步说清楚:
1. 确定C#属性对应的JSON属性名称
JSON.Net的命名规则遵循特性优先、局部覆盖全局的逻辑,优先级从高到低是这样的:
- 属性级
[JsonProperty]特性:如果你的C#属性直接标注了[JsonProperty("自定义名称")],不管其他配置,最终的JSON属性名就是这个指定的字符串——这是最高优先级,完全覆盖其他规则。 - 类级
[JsonObject]命名策略:如果你的类标注了[JsonObject(NamingStrategyType = typeof(xxxNamingStrategy))](比如CamelCaseNamingStrategy、SnakeCaseNamingStrategy),那么没有单独加JsonProperty的属性,会用这个类级策略转换名称。 - 全局
JsonSerializerSettings的契约解析器:如果你的序列化配置里指定了ContractResolver(比如CamelCasePropertyNamesContractResolver,或者自定义的DefaultContractResolver并设置了NamingStrategy),那些既没有属性级特性、也没有类级策略的属性,会用这个全局策略生成JSON名称。 - 特殊情况:DataContract特性:如果你的类标注了
[DataContract],那么JSON.Net会优先尊重属性上的[DataMember(Name = "xxx")]指定的名称;如果没有DataMember,才会遵循上面的命名策略。 - 忽略属性:如果属性标注了
[JsonIgnore],这个属性不会被序列化,自然也就没有对应的JSON属性名称。
举个直观的例子:
[JsonObject(NamingStrategyType = typeof(KebabCaseNamingStrategy))] public class User { [JsonProperty("user_id")] public int Id { get; set; } public string FullName { get; set; } [JsonIgnore] public string Password { get; set; } } // 序列化配置 var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
这个例子里:
Id对应的JSON名称是user_id(属性级特性优先)FullName对应的是full-name(类级的短横线策略覆盖了全局的驼峰策略)Password不会出现在JSON里(被忽略)
2. 判断JSON属性名称映射到哪个C#属性
反序列化的映射逻辑和序列化是反向的,但同样遵循特性优先、匹配规则明确的原则:
- 精确匹配特性指定的名称:先找C#属性上
[JsonProperty("JSON键名")]完全匹配的,或者类标注[DataContract]时[DataMember(Name = "JSON键名")]的属性,找到就直接映射。 - 按命名策略反向转换匹配:如果没有精确匹配的,就用当前生效的命名策略把JSON键名转换成C#属性名称,再去类里找对应的属性。比如全局用驼峰策略,JSON里的
fullName会转成FullName去匹配;如果是蛇形策略,full_name会转成FullName。 - 大小写敏感性控制:默认情况下,JSON.Net的名称匹配是大小写不敏感的;但如果你在
ContractResolver里设置了IgnoreCase = false,就会严格区分大小写,比如JSON的fullname和C#的FullName就不会匹配。 - 未匹配属性的兜底:如果类里有标注
[JsonExtensionData]的属性(通常是Dictionary<string, object>类型),所有找不到对应C#属性的JSON键值对,都会被自动放到这个字典里,不会抛出反序列化错误。
举个反序列化的例子:
public class Product { [JsonProperty("prod_id")] public int ProductId { get; set; } public string ProductName { get; set; } [JsonExtensionData] public Dictionary<string, object> Extra { get; set; } } // 待反序列化的JSON:{"prod_id":1, "productName":"Apple", "color":"Red"}
映射结果:
prod_id匹配到ProductId属性productName(驼峰格式)匹配到ProductName(默认大小写不敏感+全局驼峰策略反向转换)color没有对应的C#属性,会被放到Extra字典里
内容的提问来源于stack exchange,提问作者eoldre
相关产品推荐
相关产品推荐

