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

如何在运行时动态定义泛型类型时将DataTable转换为泛型列表?

动态生成类型并将DataTable转换为泛型List

方法一:生成强类型泛型List(运行时创建类型)

这种方法会根据DataTable的列结构,动态生成一个带string类型属性的.NET类,再将DataTable行转换为该类的实例,最终生成List<动态类型>。

实现代码

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

public static class DataTableHelper
{
    // 根据DataTable列动态创建类型
    public static Type CreateDynamicType(DataTable dt)
    {
        var assemblyName = new AssemblyName($"DynamicTypes_{Guid.NewGuid()}");
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
        
        var typeBuilder = moduleBuilder.DefineType($"DynamicRow_{Guid.NewGuid()}", 
            TypeAttributes.Public | TypeAttributes.Class);
        
        // 为每列添加string类型属性
        foreach (DataColumn col in dt.Columns)
        {
            // 私有字段
            var field = typeBuilder.DefineField($"_{col.ColumnName}", typeof(string), FieldAttributes.Private);
            // 属性定义
            var property = typeBuilder.DefineProperty(col.ColumnName, PropertyAttributes.None, typeof(string), null);
            
            // Get方法
            var getMethod = typeBuilder.DefineMethod($"get_{col.ColumnName}", 
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
                typeof(string), Type.EmptyTypes);
            var getIl = getMethod.GetILGenerator();
            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, field);
            getIl.Emit(OpCodes.Ret);
            
            // Set方法
            var setMethod = typeBuilder.DefineMethod($"set_{col.ColumnName}", 
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
                typeof(void), new[] { typeof(string) });
            var setIl = setMethod.GetILGenerator();
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, field);
            setIl.Emit(OpCodes.Ret);
            
            property.SetGetMethod(getMethod);
            property.SetSetMethod(setMethod);
        }
        
        return typeBuilder.CreateType();
    }
    
    // 转换DataTable为动态类型泛型列表
    public static IList ConvertToDynamicList(DataTable dt)
    {
        var dynamicType = CreateDynamicType(dt);
        var listType = typeof(List<>).MakeGenericType(dynamicType);
        var list = Activator.CreateInstance(listType) as IList;
        
        var properties = dynamicType.GetProperties();
        
        foreach (DataRow row in dt.Rows)
        {
            var instance = Activator.CreateInstance(dynamicType);
            foreach (var prop in properties)
            {
                var value = row[prop.Name] != DBNull.Value ? row[prop.Name].ToString() : null;
                prop.SetValue(instance, value);
            }
            list.Add(instance);
        }
        
        return list;
    }
}

调用示例

// 你的原有SQL查询代码
string sqlQuery = "SELECT Z.Column2, A.Column1, C.* FROM Z LEFT JOIN A ON A.ID = Z.AId bla bla bla"; 
var con = new SqlConnection();
con.ConnectionString = "你的连接字符串";
con.Open();

SqlDataAdapter da = new SqlDataAdapter(sqlQuery, con);
DataTable resultDt = new DataTable();
da.Fill(resultDt);
con.Close();

// 转换为动态泛型列表
var dynamicList = DataTableHelper.ConvertToDynamicList(resultDt);

// 遍历访问(用dynamic关键字)
foreach (var item in dynamicList)
{
    dynamic rowItem = item;
    // 根据实际查询的列名访问属性
    Console.WriteLine($"Column2: {rowItem.Column2}, Column1: {rowItem.Column1}");
}

优化建议

如果同一结构的DataTable需要多次转换,可以缓存生成的类型,避免重复创建提升性能:

// 缓存字典,键用列名+类型的组合标识
private static readonly Dictionary<string, Type> _typeCache = new Dictionary<string, Type>();

public static Type GetOrCreateDynamicType(DataTable dt)
{
    // 生成唯一标识键:列名+类型拼接
    var key = string.Join("|", dt.Columns.Cast<DataColumn>().Select(c => $"{c.ColumnName}:{c.DataType}"));
    if (_typeCache.TryGetValue(key, out Type type))
    {
        return type;
    }
    type = CreateDynamicType(dt);
    _typeCache[key] = type;
    return type;
}

方法二:使用ExpandoObject简化实现

如果不需要真正的强类型,只是需要动态访问属性的列表,可以直接用ExpandoObject,代码更简洁:

实现代码

using System;
using System.Data;
using System.Collections.Generic;
using System.Dynamic;

public static List<dynamic> ConvertToExpandoList(DataTable dt)
{
    var list = new List<dynamic>();
    foreach (DataRow row in dt.Rows)
    {
        dynamic expando = new ExpandoObject();
        var expandoDict = (IDictionary<string, object>)expando;
        
        foreach (DataColumn col in dt.Columns)
        {
            expandoDict[col.ColumnName] = row[col] != DBNull.Value ? row[col].ToString() : null;
        }
        
        list.Add(expando);
    }
    return list;
}

调用示例

var expandoList = ConvertToExpandoList(resultDt);
foreach (var item in expandoList)
{
    Console.WriteLine($"Column2: {item.Column2}, Column1: {item.Column1}");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:32:52