如何在System.Text.Json中使用JsonConstructor特性解决反序列化报错
问题原因
首次报错原因
最初的JSON外层使用{}包裹,属于JSON对象结构,而你尝试反序列化为List<AbilityTemplate>数组类型,二者结构不匹配导致反序列化失败,后续将外层改为[]的操作是正确的。
二次报错原因
有三个核心问题共同触发异常:
- 构造函数参数与属性映射不匹配:System.Text.Json要求带
[JsonConstructor]标记的构造函数的每个参数,必须对应到类的一个公共属性/字段,匹配规则默认区分大小写。你的JSON使用小驼峰命名(如id),如果类属性是帕斯卡命名(如Id),默认会匹配失败。 - 字符串数字无法自动转数值类型:JSON里
price、size都是带引号的字符串格式,而构造函数对应参数是int类型,System.Text.Json默认不会自动将字符串数字转为数值类型。 - 枚举默认不支持字符串反序列化:
Rarity是枚举类型,默认System.Text.Json只能反序列化数字格式的枚举值,你JSON里是字符串格式的枚举名,没有配置对应转换器的情况下会反序列化失败。
解决方法
- 配置反序列化参数:在调用
Deserialize方法时传入JsonSerializerOptions,开启所需的配置:
var jsonOptions = new JsonSerializerOptions { // 允许不区分大小写匹配属性名,兼容小驼峰JSON和帕斯卡类属性 PropertyNameCaseInsensitive = true, // 允许从字符串读取数字,解决JSON字符串数字转int的问题 NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString, // 添加枚举字符串转换器,支持字符串转枚举 Converters = { new JsonStringEnumConverter() } };
如果不想全局开启不区分大小写匹配,也可以给每个属性添加[JsonPropertyName]特性显式指定JSON对应的键名,示例:
public class AbilityTemplate { [JsonPropertyName("id")] public string Id { get; } [JsonPropertyName("price")] public int Price { get; } // 其余属性同理配置 }
- 确认类属性可访问性:确保
AbilityTemplate的所有对应属性(Id、Price、Size、Rarity、AbilityEffectFactory)为公共属性,如果属性为私有需要额外添加[JsonInclude]标记。 - 修改反序列化代码:将配置传入反序列化方法即可:
string text = File.ReadAllText(Path.Combine(EntityDirectory, @"Json\AbilityTemplates.json")); foreach (AbilityTemplate template in JsonSerializer.Deserialize<List<AbilityTemplate>>(text, jsonOptions)) { loaderInterface.AddAbilityTemplate(template); }
内容的提问来源于stack exchange,提问作者martinrhan
相关产品推荐
相关产品推荐

