如何用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
相关产品推荐
相关产品推荐

