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

C#中JSON反序列化时高效展开嵌套属性的实现方法

如何高效反序列化嵌套JSON数组并展开属性到C#对象列表?

作为.NET新手,你需要将带嵌套properties字段的JSON数组,转换为没有嵌套字段的Fruit类实例列表,且不想用手动遍历赋值的方式,以下是两种更高效、易维护的方案,均基于.NET内置的System.Text.Json库实现:

方案一:自定义JSON转换器(推荐复杂场景)

通过实现JsonConverter<Fruit>,让序列化库自动处理嵌套属性的映射,无需手动遍历数组元素。

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

public class Fruit
{
    public string Name { get; set; }
    public string Color { get; set; }
    public string Flavor { get; set; }
}

// 自定义转换器,处理嵌套属性展开
public class FruitConverter : JsonConverter<Fruit>
{
    public override Fruit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException("JSON格式错误,预期对象起始标记");
        }

        var fruit = new Fruit();
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                return fruit;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                string propName = reader.GetString();
                reader.Read();

                switch (propName.ToLower())
                {
                    case "name":
                        fruit.Name = reader.GetString();
                        break;
                    case "properties":
                        // 解析嵌套的properties对象
                        while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
                        {
                            if (reader.TokenType == JsonTokenType.PropertyName)
                            {
                                string nestedProp = reader.GetString();
                                reader.Read();
                                switch (nestedProp.ToLower())
                                {
                                    case "color":
                                        fruit.Color = reader.GetString();
                                        break;
                                    case "flavor":
                                        fruit.Flavor = reader.GetString();
                                        break;
                                }
                            }
                        }
                        break;
                }
            }
        }

        throw new JsonException("JSON格式不完整");
    }

    // 若不需要序列化Fruit对象,可保留默认实现
    public override void Write(Utf8JsonWriter writer, Fruit value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main()
    {
        string json = "[{\"name\":\"apple\",\"properties\":{\"color\":\"red\",\"flavor\":\"sweet\"}},{\"name\":\"orange\",\"properties\":{\"color\":\"orange\",\"flavor\":\"sour\"}}]";

        var options = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            Converters = { new FruitConverter() } // 注册自定义转换器
        };

        // 直接反序列化为目标类型列表
        List<Fruit> fruits = JsonSerializer.Deserialize<List<Fruit>>(json, options);

        foreach (var fruit in fruits)
        {
            Console.WriteLine($"Name: {fruit.Name}");
            Console.WriteLine($"Color: {fruit.Color}");
            Console.WriteLine($"Flavor: {fruit.Flavor}\n");
        }
    }
}

方案二:使用中间DTO类(推荐简单场景)

先定义与JSON结构完全匹配的中间数据传输对象(DTO),反序列化后通过LINQ投影转换为Fruit列表,代码简洁易读。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;

public class Fruit
{
    public string Name { get; set; }
    public string Color { get; set; }
    public string Flavor { get; set; }
}

// 中间DTO,完全匹配JSON的嵌套结构
public class FruitDto
{
    public string Name { get; set; }
    public PropertiesDto Properties { get; set; }
}

public class PropertiesDto
{
    public string Color { get; set; }
    public string Flavor { get; set; }
}

class Program
{
    static void Main()
    {
        string json = "[{\"name\":\"apple\",\"properties\":{\"color\":\"red\",\"flavor\":\"sweet\"}},{\"name\":\"orange\",\"properties\":{\"color\":\"orange\",\"flavor\":\"sour\"}}]";

        var options = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        };

        // 先反序列化为DTO列表
        List<FruitDto> fruitDtos = JsonSerializer.Deserialize<List<FruitDto>>(json, options);

        // 通过LINQ投影转换为目标类型
        List<Fruit> fruits = fruitDtos.Select(dto => new Fruit
        {
            Name = dto.Name,
            Color = dto.Properties.Color,
            Flavor = dto.Properties.Flavor
        }).ToList();

        foreach (var fruit in fruits)
        {
            Console.WriteLine($"Name: {fruit.Name}");
            Console.WriteLine($"Color: {fruit.Color}");
            Console.WriteLine($"Flavor: {fruit.Flavor}\n");
        }
    }
}

方案对比

  • 自定义转换器:适用于复杂嵌套结构或需要自定义解析逻辑的场景,一次配置可重复使用,性能最优。
  • 中间DTO类:代码简洁、学习成本低,适用于简单映射场景,性能略逊于转换器但远优于手动遍历。

这两种方案均利用System.Text.Json的内置优化,避免了手动操作JsonElement的繁琐,代码更易维护。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:12:04