JSON2CSharp转换器为何自动生成[JsonProperty]特性?
我从某API接口得到如下JSON响应:
{ "arguments": { "Configuration": { "Building_Configuration.Parameters_SP.fixtureStrategy_SP": "ETA", "Building_Configuration.Parameters_SP.dimensionSelection_SP": "Imperial", "Building_Configuration.Parameters_SP.controllerRobotic_SP": false, "Building_Configuration.Parameters_SP.controllerBACNet_SP": false } } }
我在Visual Studio 2019的C#项目中,使用JSON to C# Converter工具,生成了与上述JSON结构对应的Root.cs模型文件,代码如下:
public class Root { public Arguments arguments { get; set; } } public class Arguments { public Configuration Configuration { get; set; } } public class Configuration { [JsonProperty("Building_Configuration.Parameters_SP.fixtureStrategy_SP")] public string BuildingConfigurationParametersSPFixtureStrategySP { get; set; } [JsonProperty("Building_Configuration.Parameters_SP.dimensionSelection_SP")] public string BuildingConfigurationParametersSPDimensionSelectionSP { get; set; } [JsonProperty("Building_Configuration.Parameters_SP.controllerRobotic_SP")] public bool BuildingConfigurationParametersSPControllerRoboticSP { get; set; } [JsonProperty("Building_Configuration.Parameters_SP.controllerBACNet_SP")] public bool BuildingConfigurationParametersSPControllerBACNetSP { get; set; } }
我通过如下代码尝试访问并返回Configuration类的第一个属性BuildingConfigurationParametersSPFixtureStrategySP的值:
public string CreateExecPost() { /*...此处其余代码运行均正常,可通过断点逐行调试查看所有变量值,无异常 ....*/ var payload = new StringContent(newPost, Encoding.UTF8, "application/json"); var result = client.PostAsync(endpoint, payload).Result.Content.ReadAsStringAsync().Result; Root MyObject = JsonConvert.DeserializeObject<Root>(result); return MyObject.arguments.Configuration.BuildingConfigurationParametersSPFixtureStrategySP; } // BuildingConfigurationParametersSPFixtureStrategySP可正确返回预期值,功能运行正常
运行代码后可正确获取目标属性值,功能运行正常。但我存在如下疑问:为什么转换器会在每个属性的{ get; set; }语句上方,生成形如[JsonProperty("Building_Configuration.Parameters_SP.fixtureStrategy_SP")]的特性?我已经查阅过JsonProperty、JsonPropertyAttribute的相关技术资料,但仍未完全理解:工具是依据什么规则判断需要生成该特性,生成该特性的作用是什么?
工具生成[JsonProperty]特性的判断规则
这个特性不是随机生成的,工具的判断逻辑非常明确:只要JSON字段名无法直接作为合法C#属性名使用,或是转换后的C#属性名和原JSON字段名不一致,就会自动添加该特性做映射。
你拿到的JSON中Configuration节点下的字段名都包含.,比如Building_Configuration.Parameters_SP.fixtureStrategy_SP,而.在C#语法中是对象成员访问运算符,属于语法保留符号,根本不允许出现在属性名、变量名这类标识符中。工具不可能直接把带.的字符串作为C#属性名,因此会自动移除字段名中的.、_等特殊字符,按照C#常用的帕斯卡命名规则拼接成合法的属性名,也就是你看到的移除所有点后的BuildingConfigurationParametersSPFixtureStrategySP这类名称。
这时候就出现了名称不匹配的问题:JSON中存储的字段名是带.的,C#中的属性名是移除特殊字符后的,两者名称无法对应,序列化、反序列化时就会匹配失败,因此工具必须添加[JsonProperty]特性显式声明两者的绑定关系。
你可以对照观察上层的arguments、Configuration两个属性,工具就没有添加该特性,因为这两个JSON字段名本身没有非法字符,转换后的C#属性名和原JSON字段名能被Newtonsoft.Json的默认匹配规则识别,不需要额外做映射。
该特性的作用
你代码中使用的JsonConvert属于Newtonsoft.Json序列化库,[JsonProperty]就是这个库提供的映射特性,核心作用是显式指定C#属性和JSON字段的对应关系,绕过默认的名称匹配逻辑:
- 反序列化(将JSON字符串转换为C#对象)时,库不会查找与C#属性名同名的JSON字段,而是直接定位特性参数中传入的名称对应的JSON字段,将值赋值给被标注的C#属性
- 序列化(将C#对象转换为JSON字符串)时,库也不会使用C#属性本身的名称作为JSON字段名,而是直接输出特性中指定的名称
如果删除这些特性再运行代码,你会发现Configuration类下的四个属性全都会返回默认值:字符串类型返回null,布尔类型返回false。原因很简单,库找不到和BuildingConfigurationParametersSPFixtureStrategySP这类C#属性名同名的JSON字段——毕竟JSON里的字段都带.,和C#属性名完全不一致,自然无法匹配。你现在的代码能正常拿到正确值,本质就是这些特性完成了正确的名称映射。
内容的提问来源于stack exchange,提问作者Jeff

