You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用System.Text.Json阻止只读集合序列化?IgnoreReadOnlyProperties无效

System.Text.Json 只读集合序列化问题解答

问题现象与疑问

创建包含只读集合属性的类,使用System.Text.Json.JsonSerializer并配置JsonSerializerOptions.IgnoreReadOnlyProperties = true时,普通只读属性(如ReadOnlyInt)未被序列化,但只读集合属性(ReadOnlyCollection)仍被序列化;反序列化时所有只读属性均被忽略,符合预期。

疑问:

  1. 序列化时为何对集合区别对待?
  2. 能否不使用[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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:20:35