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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:45:33