System.Text.Json反序列化报固定大小集合异常是使用错误还是Bug
核心结论
你遇到的不是历史已关闭bug的复现,也不是使用方式错误,本质是System.Text.Json和Newtonsoft.Json对集合属性反序列化的默认实现逻辑存在差异。
原因说明
两个库的集合反序列化逻辑区别如下:
- Newtonsoft.Json反序列化集合属性时,会先完整构造出反序列化后的集合对象,再调用属性的set方法完成赋值,全程不会调用属性getter取现有集合做修改。你的ClassB中ArrayOfString的set逻辑只要接收到长度为1的字符串数组,就会把值同步给基类的SingularString属性,因此可以正常运行。
- System.Text.Json对可写集合属性默认采用填充现有集合的逻辑:它会先调用属性getter拿到已存在的集合实例,再把JSON中解析出的元素逐个添加到这个集合中,默认不会在解析完所有元素后调用属性set方法。
你的ArrayOfString属性getter每次返回的是长度固定为1的新字符串数组,数组本身是固定长度结构,不支持Add/Insert等会修改集合长度的操作,因此System.Text.Json尝试往里面添加元素时,直接抛出「Collection was of a fixed size」异常,你写的set逻辑根本不会被执行。
解决方法
两种方案可按需选择,优先推荐第一种,改动成本最低:
- 修改System.Text.Json的对象创建处理配置,强制它对集合采用替换逻辑,和Newtonsoft.Json行为对齐:反序列化时生成新的集合实例后调用属性set赋值,不会再调用getter取现有集合填充。
全局配置示例:
单属性配置(.NET 7及以上版本支持,不需要改全局配置):var jsonOptions = new JsonSerializerOptions { PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace }; ClassB classB = System.Text.Json.JsonSerializer.Deserialize<ClassB>(json, jsonOptions);class ClassB : BaseClass { [System.Text.Json.Serialization.JsonObjectCreationHandling(JsonObjectCreationHandling.Replace)] public string[] ArrayOfString { get => new string[] { base.SingularString }; set { if((value != null) && (value.Length == 1)) { base.SingularString = value[0]; } } } } class BaseClass { public string SingularString { get; set; } = "Hello World"; } - 调整属性实现逻辑,不要让getter返回固定大小的数组,这种方案改动成本更高,更适合属性本身确实需要持有集合实例的场景,你当前同步单值到基类的场景不需要用这种方式。
内容的提问来源于stack exchange,提问作者IV.
相关产品推荐
相关产品推荐

