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

C#反射实现嵌套对象填充:DataTable递归赋值需求

递归反射实现DataTable到嵌套对象集合的转换

核心思路

通过递归反射遍历目标类型的所有属性,根据属性类型区分处理:

  • 对于值类型、字符串或可空类型,直接从DataTable行中匹配同名列赋值
  • 对于引用类型(非字符串),检查DataTable中是否存在以父属性名_为前缀的列,若存在则递归创建并填充嵌套对象,无需额外数据库查询

完整实现代码

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

public static class ReflectConverter
{
    /// <summary>
    /// 将DataTable转换为指定类型的对象集合
    /// </summary>
    /// <typeparam name="T">目标对象类型</typeparam>
    /// <param name="dt">数据源DataTable</param>
    /// <returns>对象集合</returns>
    public static List<T> Reflect<T>(DataTable dt) where T : new()
    {
        var resultList = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            resultList.Add(CreateAndFillNestedObject<T>(row));
        }
        return resultList;
    }

    /// <summary>
    /// 递归创建并填充对象(包括嵌套子对象)
    /// </summary>
    private static T CreateAndFillNestedObject<T>(DataRow row) where T : new()
    {
        var targetObj = new T();
        var targetType = typeof(T);

        foreach (PropertyInfo prop in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var propType = prop.PropertyType;
            var nestedColumnPrefix = $"{prop.Name}_";

            // 处理值类型、字符串、可空值类型
            if (IsSimpleType(propType))
            {
                if (row.Table.Columns.Contains(prop.Name))
                {
                    var columnValue = row[prop.Name];
                    if (columnValue != DBNull.Value)
                    {
                        prop.SetValue(targetObj, Convert.ChangeType(columnValue, GetUnderlyingType(propType)));
                    }
                }
            }
            // 处理引用类型(递归创建子对象)
            else if (propType.IsClass && propType != typeof(string))
            {
                // 检查是否存在该嵌套对象对应的列(如Bar_Id、Bar_SubBar_Detail)
                bool hasNestedColumns = row.Table.Columns.Cast<DataColumn>()
                    .Any(col => col.ColumnName.StartsWith(nestedColumnPrefix));

                if (hasNestedColumns)
                {
                    // 动态调用泛型方法创建子对象
                    var createMethod = typeof(ReflectConverter)
                        .GetMethod(nameof(CreateAndFillNestedObject), BindingFlags.NonPublic | BindingFlags.Static)
                        ?.MakeGenericMethod(propType);

                    if (createMethod != null)
                    {
                        var nestedObj = createMethod.Invoke(null, new object[] { row });
                        prop.SetValue(targetObj, nestedObj);
                    }
                }
            }
        }

        return targetObj;
    }

    /// <summary>
    /// 判断是否为简单类型(值类型、字符串、可空值类型)
    /// </summary>
    private static bool IsSimpleType(Type type)
    {
        return type.IsValueType 
            || type == typeof(string) 
            || Nullable.GetUnderlyingType(type) != null;
    }

    /// <summary>
    /// 获取可空类型的基础类型,非空类型则返回原类型
    /// </summary>
    private static Type GetUnderlyingType(Type type)
    {
        return Nullable.GetUnderlyingType(type) ?? type;
    }
}

关键细节说明

  1. 列名约定:嵌套对象的属性需对应DataTable中父属性名_子属性名格式的列,例如Bar_SubBar_Detail对应Foo.Bar.SubBar.Detail,这样可以直接从同一张表提取嵌套数据,无需额外查询
  2. 递归扩展性:无论后续给Bar、Cas新增多少层子对象,只要列名遵循约定,递归逻辑会自动处理,无需修改转换方法
  3. 类型安全处理:封装了IsSimpleType和GetUnderlyingType方法,统一处理值类型、可空类型和引用类型的赋值逻辑,避免类型转换异常
  4. 空值处理:判断列值是否为DBNull.Value,避免将数据库空值赋值给对象属性导致的错误

使用示例

实体类定义

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Bar Bar { get; set; }
    public Cas Cas { get; set; }
}

public class Bar
{
    public int Id { get; set; }
    public string Title { get; set; }
    // 后续新增的子对象
    public SubBar SubBar { get; set; }
}

public class Cas
{
    public string Code { get; set; }
}

public class SubBar
{
    public string Detail { get; set; }
}

调用方式

// 假设从数据库获取包含以下列的DataTable:
// Id, Name, Bar_Id, Bar_Title, Bar_SubBar_Detail, Cas_Code
DataTable dataTable = FetchDataFromDatabase();
List<Foo> fooCollection = ReflectConverter.Reflect<Foo>(dataTable);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:50:52