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

实现IReadOnlyCollection的类无法用System.Text.Json反序列化的问题

问题分析与解决方案

你的问题核心是:System.Text.Json默认会将实现IReadOnlyCollection<T>等集合接口的类视为「集合类型」,反序列化时优先走集合的添加逻辑而非对象构造逻辑。哪怕你标记了[JsonConstructor],序列化器也不会调用它——因为它觉得这是个集合,应该创建实例后往里面加元素,但你的MyItems是只读集合,没有Add方法,所以抛出NotSupportedException。

参数名称不是问题,因为JSON是数组结构(而非键值对),序列化器会直接把数组内容传给构造函数的可枚举类型参数,只要参数类型匹配(比如IEnumerable<int>、int[]、List<int>)即可。

可选解决方案(无需自定义Converter优先)

1. 用[JsonObject]标记类,强制序列化器当作对象处理

给MyItems类加上[JsonObject]特性,告诉System.Text.Json:这不是普通集合,是一个需要通过构造函数实例化的对象。

示例代码:

using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;

[JsonObject]
public class MyItems : IReadOnlyCollection<int>
{
    private readonly List<int> _items;

    [JsonConstructor]
    public MyItems(IEnumerable<int> items)
    {
        _items = new List<int>(items);
    }

    public int Count => _items.Count;

    public IEnumerator<int> GetEnumerator() => _items.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

这样反序列化时,序列化器会自动解析JSON数组,将其作为参数传入标记了[JsonConstructor]的构造函数,无需额外转换器。

自定义Converter方案(更灵活的场景)

如果你的MyItems有复杂的逻辑,或者不想依赖[JsonObject]特性,可以自定义JsonConverter来完全控制序列化/反序列化流程:

public class MyItemsConverter : JsonConverter<MyItems>
{
    public override MyItems Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 先把JSON数组反序列化为List<int>,再传入构造函数
        var items = JsonSerializer.Deserialize<List<int>>(ref reader, options);
        return new MyItems(items);
    }

    public override void Write(Utf8JsonWriter writer, MyItems value, JsonSerializerOptions options)
    {
        // 序列化时直接把MyItems当作IEnumerable<int>输出
        JsonSerializer.Serialize(writer, value as IEnumerable<int>, options);
    }
}

然后给MyItems类添加转换器标记:

[JsonConverter(typeof(MyItemsConverter))]
public class MyItems : IReadOnlyCollection<int>
{
    // ... 类实现代码 ...
}

或者在序列化/反序列化时传入配置:

var options = new JsonSerializerOptions();
options.Converters.Add(new MyItemsConverter());

var myItems = JsonSerializer.Deserialize<MyItems>("[1,2,3]", options);

不推荐的方案

不要为了适配序列化而给只读集合添加Add方法(实现ICollection<int>),这会破坏只读集合的设计意图,导致类的行为不符合预期。

内容的提问来源于stack exchange,提问作者grim.ub

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:03:12