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

如何用Newtonsoft将JSON反序列化为强类型数值数组而非Object[]?

解决Newtonsoft解析JSON数组为强类型数组的问题

嘿,我正好碰到过类似的困扰!Newtonsoft的ExpandoObjectConverter为了兼容所有可能的JSON结构,确实会把数组默认解析成Object[]或者List<object>,不会自动推断元素的统一强类型。不过我们可以通过两种思路来解决这个问题:在解析阶段直接生成强类型数组,或者解析后对已有数组进行递归转换。

方案一:自定义JsonConverter,解析时直接生成强类型数组

我们可以写一个自定义的转换器,在解析JSON数组时自动推断元素的统一类型,然后生成对应类型的数组(比如int[]、double[]),同时支持嵌套数组的递归处理。

自定义转换器代码

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Dynamic;

public class StrongTypedArrayConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // 支持object、数组或列表类型的转换
        return objectType == typeof(object) || objectType.IsArray || typeof(IList).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        // 加载JSON数组
        var jArray = JArray.Load(reader);
        if (jArray.Count == 0)
            return Array.CreateInstance(typeof(object), 0); // 空数组可根据需求调整返回类型

        // 推断所有元素的统一类型
        Type elementType = InferElementType(jArray);

        // 创建对应类型的数组并填充元素
        Array resultArray = Array.CreateInstance(elementType, jArray.Count);
        for (int i = 0; i < jArray.Count; i++)
        {
            var item = jArray[i].ToObject(elementType, serializer);
            resultArray.SetValue(item, i);
        }

        return resultArray;
    }

    private Type InferElementType(JArray jArray)
    {
        Type commonType = null;
        foreach (var jToken in jArray)
        {
            Type currentType = GetTokenType(jToken);
            if (commonType == null)
            {
                commonType = currentType;
            }
            else if (commonType != currentType)
            {
                // 若类型不统一,可抛出异常或回退到object[],根据你的业务需求调整
                throw new JsonSerializationException("JSON数组元素类型不统一,无法转换为强类型数组");
            }
        }
        return commonType ?? typeof(object);
    }

    private Type GetTokenType(JToken jToken)
    {
        return jToken.Type switch
        {
            JTokenType.Integer => typeof(int), // 若JSON整数可能为long,可改为typeof(long)
            JTokenType.Float => typeof(double),
            JTokenType.Object => typeof(ExpandoObject), // 嵌套对象用ExpandoObject,也可替换为你的自定义字典类型
            JTokenType.Array => typeof(Array), // 嵌套数组递归处理
            _ => typeof(object)
        };
    }

    // 只处理反序列化,序列化用默认逻辑
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

使用方式

把自定义转换器和ExpandoObjectConverter一起加入序列化配置即可:

var json = @"
{
    ""intArray"": [1, 2, 3],
    ""doubleArray"": [1.5, 2.7, 4.9],
    ""nestedArray"": [[10, 20], [30, 40]]
}";

var settings = new JsonSerializerSettings();
settings.Converters.Add(new StrongTypedArrayConverter());
settings.Converters.Add(new ExpandoObjectConverter());

dynamic result = JsonConvert.DeserializeObject<ExpandoObject>(json, settings);

// 现在可以直接强转成对应类型的数组
int[] intArr = result.intArray;
double[] doubleArr = result.doubleArray;
int[][] nestedArr = (int[][])result.nestedArray;

方案二:解析后递归转换为强类型数组

如果已经用默认的ExpandoObjectConverter完成了解析,得到了Object[]或List<object>,可以写一个递归转换方法,把这些弱类型数组转成强类型。

递归转换扩展方法

using System;
using System.Collections.Generic;
using System.Linq;

public static class ArrayConversionExtensions
{
    public static object ConvertToStrongTypedArray(this IEnumerable<object> source)
    {
        if (source == null) return null;
        var list = source.ToList();
        if (list.Count == 0) return Array.Empty<object>();

        // 推断元素的统一类型
        Type elementType = InferElementType(list);
        Array result = Array.CreateInstance(elementType, list.Count);

        for (int i = 0; i < list.Count; i++)
        {
            object item = list[i];
            // 若元素是嵌套数组/列表,递归转换
            if (item is IEnumerable<object> nestedList)
            {
                item = nestedList.ConvertToStrongTypedArray();
            }
            // 转换元素到目标类型
            var convertedItem = Convert.ChangeType(item, elementType);
            result.SetValue(convertedItem, i);
        }

        return result;
    }

    private static Type InferElementType(List<object> list)
    {
        Type commonType = null;
        foreach (var item in list)
        {
            Type currentType = item.GetType();
            // 嵌套数组统一按Array类型处理
            if (currentType.IsArray || typeof(IEnumerable<object>).IsAssignableFrom(currentType))
            {
                currentType = typeof(Array);
            }

            if (commonType == null)
            {
                commonType = currentType;
            }
            else if (commonType != currentType)
            {
                throw new InvalidOperationException("数组元素类型不统一,无法转换为强类型数组");
            }
        }
        return commonType ?? typeof(object);
    }
}

使用方式

// 先用默认转换器解析
dynamic rawResult = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());

// 对每个数组进行转换
int[] intArr = (int[])((IEnumerable<object>)rawResult.intArray).ConvertToStrongTypedArray();
double[] doubleArr = (double[])((IEnumerable<object>)rawResult.doubleArray).ConvertToStrongTypedArray();

注意事项

  • 如果JSON中的整数可能超出int范围(比如long类型),需要在InferElementType方法中调整对应的类型判断。
  • 若业务允许数组存在混合类型,可以修改类型推断逻辑,回退到object[]而不是抛出异常。
  • 嵌套对象如果需要转成自定义字典类型,只需修改GetTokenType中JTokenType.Object对应的返回类型即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:55:37