C#中如何泛型解析无键JSON数组到对象?
通用解决方案:自定义Json转换器按声明顺序映射数组到对象
要解决无键JSON数组按类成员声明顺序映射到对象的问题,可以编写一个通用的JsonConverter,通过反射获取类成员的声明顺序,自动将数组元素对应赋值,支持嵌套类结构。
步骤1:实现通用转换器
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; public class ArrayToObjectConverter : JsonConverter { // 控制是否处理字段,可根据需求调整为属性 private readonly bool _includeFields = true; private readonly BindingFlags _bindingFlags = BindingFlags.Public | BindingFlags.Instance; public ArrayToObjectConverter() { } public ArrayToObjectConverter(bool includeFields) { _includeFields = includeFields; } public override bool CanConvert(Type objectType) { // 只处理自定义类(排除值类型、数组、字符串等) return !objectType.IsValueType && !objectType.IsArray && objectType != typeof(string); } 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); var obj = Activator.CreateInstance(objectType); // 获取类成员(按声明顺序) var members = _includeFields ? objectType.GetFields(_bindingFlags).OrderBy(f => f.MetadataToken).Cast<MemberInfo>() : objectType.GetProperties(_bindingFlags).OrderBy(p => p.MetadataToken).Cast<MemberInfo>(); // 遍历成员,按顺序从数组取对应值赋值 for (int i = 0; i < members.Count(); i++) { if (i >= jArray.Count) break; // 数组元素不足时跳过 var member = members.ElementAt(i); var value = jArray[i].ToObject(GetMemberType(member), serializer); switch (member) { case FieldInfo field: field.SetValue(obj, value); break; case PropertyInfo prop: if (prop.CanWrite) prop.SetValue(obj, value); break; } } return obj; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 序列化时将对象转为数组(可选实现) var objectType = value.GetType(); var members = _includeFields ? objectType.GetFields(_bindingFlags).OrderBy(f => f.MetadataToken).Cast<MemberInfo>() : objectType.GetProperties(_bindingFlags).OrderBy(p => p.MetadataToken).Cast<MemberInfo>(); writer.WriteStartArray(); foreach (var member in members) { var memberValue = member switch { FieldInfo field => field.GetValue(value), PropertyInfo prop => prop.GetValue(value), _ => null }; serializer.Serialize(writer, memberValue); } writer.WriteEndArray(); } private Type GetMemberType(MemberInfo member) { return member switch { FieldInfo field => field.FieldType, PropertyInfo prop => prop.PropertyType, _ => throw new ArgumentException("Member is not a field or property") }; } }
步骤2:使用转换器
方式1:全局注册(推荐,所有类自动生效)
在项目启动时注册转换器,这样所有符合条件的类都会自动使用该转换器解析数组:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List<JsonConverter> { new ArrayToObjectConverter(includeFields: true) } // 这里设置是否处理字段 };
之后你的ParseTest方法无需修改即可正常运行:
private void ParseTest() { Test test = JsonConvert.DeserializeObject<Test>("[1, true, 3]"); // test.one = 1, test.trueOrFalse = true, test.three = 3 }
方式2:针对单个类添加特性
如果只需要特定类使用该转换器,可以在类上标记JsonConverter特性:
[JsonConverter(typeof(ArrayToObjectConverter))] public class Test { public uint one; public bool trueOrFalse; public uint three; }
嵌套类支持
如果你的类包含嵌套类成员,比如:
public class NestedTest { public string name; public Test nestedObj; }
对应的JSON数组["Alice", [2, false, 4]]会被自动解析,转换器会递归处理嵌套的Test类型,无需额外配置。
注意事项
MetadataToken用于保证成员按声明顺序排序,这是.NET中获取成员声明顺序的可靠方式- 转换器默认处理公共字段,如果需要处理属性,可将
includeFields设为false - 如果JSON数组元素数量少于类成员数量,剩余成员会保留默认值;如果元素数量更多,多余元素会被忽略
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

