如何用System.Text.Json阻止只读集合序列化?IgnoreReadOnlyProperties无效
System.Text.Json 只读集合序列化问题解答
问题现象与疑问
创建包含只读集合属性的类,使用System.Text.Json.JsonSerializer并配置JsonSerializerOptions.IgnoreReadOnlyProperties = true时,普通只读属性(如ReadOnlyInt)未被序列化,但只读集合属性(ReadOnlyCollection)仍被序列化;反序列化时所有只读属性均被忽略,符合预期。
疑问:
- 序列化时为何对集合区别对待?
- 能否不使用
[JsonIgnore]特性阻止只读集合属性的序列化?因序列化方式不可选,希望代码中无序列化相关特性。
测试类代码
public class TestJSONClass { public int ReadOnlyInt { get; } = 1; public IEnumerable<int> ReadOnlyCollection { get; } = new int[2]; public int ReadWriteInt { get; set; } = 3; public IEnumerable<int> ReadWriteCollection { get; set; } = new int[4]; }
序列化代码
JsonSerializerOptions options = new JsonSerializerOptions() { WriteIndented = true, IgnoreReadOnlyProperties = true }; JsonSerializer.Serialize(new TestJSONClass(), options);
当前序列化输出
{ "ReadOnlyCollection": [ 0, 0 ], "ReadWriteInt": 3, "ReadWriteCollection": [ 0, 0, 0, 0 ] }
期望序列化输出
{ "ReadWriteInt": 3, "ReadWriteCollection": [ 0, 0, 0, 0 ] }
问题解答
1. 序列化时对集合区别对待的原因
System.Text.Json的IgnoreReadOnlyProperties选项默认仅作用于值类型和非集合类引用类型的只读属性。对于集合类型的只读属性,框架设计逻辑认为:即使属性本身只有getter,集合内部的内容可能是可修改的(比如示例中的数组,属性只读但数组元素可以更改),为了保留集合的当前状态,默认会序列化这类只读集合属性。
2. 不使用[JsonIgnore]阻止只读集合序列化的方案
可以通过自定义类型信息解析器的方式过滤只读集合属性,无需在业务类中添加任何序列化特性,具体实现如下:
var options = new JsonSerializerOptions { WriteIndented = true, IgnoreReadOnlyProperties = true, TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { // 遍历并移除只读的集合属性(排除字符串) foreach (var property in typeInfo.Properties.ToList()) { if (!property.IsReadOnly) continue; var propertyType = property.PropertyType; // 判断是否为集合类型,同时排除字符串(字符串虽实现IEnumerable但视为值类型) if (typeof(System.Collections.IEnumerable).IsAssignableFrom(propertyType) && propertyType != typeof(string)) { typeInfo.Properties.Remove(property); } } } } } }; var json = JsonSerializer.Serialize(new TestJSONClass(), options);
这段代码通过DefaultJsonTypeInfoResolver的修改器,在序列化前自动移除所有只读的集合属性,最终输出与期望一致。
内容的提问来源于stack exchange,提问作者tmren
相关产品推荐
相关产品推荐

