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

使用Newtonsoft.Json反序列化字符串数组与二维字符串数组的混合负载

解决方案:自定义JsonConverter处理混合数组类型反序列化

1. 完善SingleOrArray<T>类实现

先补全SingleOrArray<T>的ICollection<T>接口实现,确保序列化和反序列化基础功能正常:

public class SingleOrArray<T> : ICollection<T>
{
    public bool IsArray { get; set; } = false;
    public T Value { get; set; }

    public T[] Values => _items.ToArray();
    private readonly List<T> _items = new();

    // ICollection<T> 接口实现
    public int Count => _items.Count;
    public bool IsReadOnly => false;

    public void Add(T item) => _items.Add(item);
    public void Clear() => _items.Clear();
    public bool Contains(T item) => _items.Contains(item);
    public void CopyTo(T[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex);
    public bool Remove(T item) => _items.Remove(item);
    public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    // 辅助方法:从单个值初始化
    public static SingleOrArray<T> FromSingleValue(T value)
    {
        return new SingleOrArray<T>
        {
            IsArray = false,
            Value = value
        };
    }

    // 辅助方法:从集合初始化
    public static SingleOrArray<T> FromCollection(IEnumerable<T> collection)
    {
        var instance = new SingleOrArray<T> { IsArray = true };
        foreach (var item in collection)
        {
            instance.Add(item);
        }
        return instance;
    }
}

2. 实现自定义JsonConverter

创建SingleOrArrayListConverter<T>,处理List<SingleOrArray<T>>的反序列化逻辑,自动判断JSON是单个数组还是数组的数组:

public class SingleOrArrayListConverter<T> : JsonConverter<List<SingleOrArray<T>>>
{
    public override List<SingleOrArray<T>> ReadJson(JsonReader reader, Type objectType, List<SingleOrArray<T>> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var result = new List<SingleOrArray<T>>();

        switch (token.Type)
        {
            // 情况1:JSON是单个数组(如 ["foo", "bar"]),将其作为单个SingleOrArray<T>的Value
            case JTokenType.Array when token.Children().All(c => c.Type != JTokenType.Array):
                var singleValue = token.ToObject<T>();
                result.Add(SingleOrArray<T>.FromSingleValue(singleValue));
                break;

            // 情况2:JSON是数组的数组(如 [["foo","bar"], ["baz","qux"]]),每个子数组作为一个SingleOrArray<T>的Value
            case JTokenType.Array when token.Children().All(c => c.Type == JTokenType.Array):
                foreach (var childToken in token.Children<JArray>())
                {
                    var value = childToken.ToObject<T>();
                    result.Add(SingleOrArray<T>.FromSingleValue(value));
                }
                break;

            default:
                throw new JsonSerializationException("无法识别的JSON格式,仅支持数组或数组的数组");
        }

        return result;
    }

    public override void WriteJson(JsonWriter writer, List<SingleOrArray<T>> value, JsonSerializer serializer)
    {
        // 序列化逻辑:如果列表只有一个元素且是单个值,直接序列化该值;否则序列化所有元素的Value组成的数组
        if (value.Count == 1 && !value[0].IsArray)
        {
            serializer.Serialize(writer, value[0].Value);
        }
        else
        {
            writer.WriteStartArray();
            foreach (var item in value)
            {
                serializer.Serialize(writer, item.IsArray ? item.Values : item.Value);
            }
            writer.WriteEndArray();
        }
    }
}

3. 定义反序列化对象

调整MyObject类,绑定自定义转换器:

public class MyObject
{
    [JsonConverter(typeof(SingleOrArrayListConverter<string[]>))]
    public List<SingleOrArray<string[]>> Values { get; set; }
}

4. 适配string[]场景的单元测试

修改测试用例,验证两种JSON格式的反序列化结果:

public class MyObjectTests
{
    [Fact]
    public void SingleArrayTest()
    {
        // Arrange
        var testData = "{ \"Values\": [ \"foo\", \"bar\" ] }";
        
        // Act
        var target = JsonConvert.DeserializeObject<MyObject>(testData);

        // Assert
        Assert.NotNull(target);
        Assert.Single(target.Values);
        var singleItem = target.Values[0];
        Assert.False(singleItem.IsArray);
        Assert.Equal(new[] { "foo", "bar" }, singleItem.Value);
    }

    [Fact]
    public void ArrayOfArraysTest()
    {
        // Arrange
        var testData = "{ \"Values\": [ [ \"foo\", \"bar\" ], [ \"baz\", \"qux\" ] ] }";
        
        // Act
        var target = JsonConvert.DeserializeObject<MyObject>(testData);

        // Assert
        Assert.NotNull(target);
        Assert.Equal(2, target.Values.Count);
        
        var firstItem = target.Values[0];
        Assert.False(firstItem.IsArray);
        Assert.Equal(new[] { "foo", "bar" }, firstItem.Value);
        
        var secondItem = target.Values[1];
        Assert.False(secondItem.IsArray);
        Assert.Equal(new[] { "baz", "qux" }, secondItem.Value);
    }
}

关键说明

  • 转换器自动识别JSON结构:
    • 单个数组(如["foo","bar"])会被包装为一个SingleOrArray<string[]>,IsArray=false,Value为该字符串数组
    • 数组的数组(如[["foo","bar"],["baz","qux"]])会拆分为多个SingleOrArray<string[]>元素,每个元素的Value对应子数组
  • 忽略混合类型JSON(如["foo",["bar"]]),遇到时抛出序列化异常

内容的提问来源于stack exchange,提问作者devlord

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:45:15