如何使用反射将 DataTable 转换为 List<T>

6

我有一个泛型类的列表,我使用Reflection和扩展方法自动将其转换为DataTable。现在我想要反向进行操作。我想要将DataTable转换为列表。更好的说法是,我想要编写一个方法来接受DataTableType,并根据列名自动查找该类型(类)的属性,并将值分配给该类型(类)的对象。像这个伪代码:

private List<T> ConvertToList<T>(DataTable dt)
{
    List<string> AllColumns = // Get All Column Names of a DataTable
    for(int i=0;i<dt.Rows.Count;i++)
    {
        foreach(var item in AllColumns )
        {
             //Get Property According To **ITEM**
             //Get Data Of Rows[i][item] and assign it to T.property
        }
    }
}

我该如何做到这一点?


编辑1)

我使用@Cuong Le的答案:

var properties = typeof(CustomType).GetProperties().ToList();
List<CustomType> list = ConvertToList<CustomType>(dt, properties);

并且:

private List<T> ConvertToList<T>(DataTable dt,List<PropertyInfo> fields) where T : class
{
    return dt.AsEnumerable().Select(Convert<T>(fields)).ToList();  <------
}

private T Convert<T>(DataRow row,List<PropertyInfo> fields) where T : class
{
    var properties = typeof(T).GetProperties().ToList();

    var objT = Activator.CreateInstance<T>();
    foreach (var pro in properties)
    {
        pro.SetValue(objT, row[pro.Name],null);
    }

    return objT;
} 

但是,在我在代码中加上箭头时,出现了两个错误:

没有重载方法'Convert'接受1个参数

无法从用法推断出方法'System.Data.EnumerableRowCollectionExtensions.Select(System.Data.EnumerableRowCollection, System.Func)'的类型参数。请明确指定类型参数。

我该如何解决这个问题?


1
如果您添加更多的输入参数,应该是:Select(row => Convert<T>(row, fields)) - cuongle
1个回答

10

使用AsEnumerable()方法来支持LINQ:

    private List<T> ConvertToList<T>(DataTable dt)
    {
        var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();

        var properties = typeof(T).GetProperties();

        return dt.AsEnumerable().Select(row =>
            {
                var objT = Activator.CreateInstance<T>();

                foreach (var pro in properties)
                {
                    if (columnNames.Contains(pro.Name))
                        pro.SetValue(objT, row[pro.Name]);
                }

                return objT;
            }).ToList();

    }

GetProperties方法用指定的绑定约束搜索当前类型(Type)的属性。

这里提供了链接:http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx


1
将光标放在“GetProperties”上,然后按F1。 - Zdeslav Vojkovic
@Kerezo:在这里看一下:http://msdn.microsoft.com/zh-cn/library/kyaxdd3x.aspx - cuongle
谢谢亲爱的@CuongLe。但是,如果DataTable拥有与T.Properties对应的所有列,则此代码有效。我该如何将列名列表传递给Convert并仅设置具有列的属性? - Arian
类似于扩展方法的一个示例:https://gist.github.com/gaui/a0a615029f1327296cf8 - Gaui
2023年我唯一看到的问题是,如果您的数据表是从数据库中填充的并包含System.DBNull值,即使对象属性可为空,它们也不会转换为null。解决方案是将pro.SetValue()行更改为:pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : row[pro.Name]); - kooch
在2023年,我唯一看到的问题是,如果你的数据表从数据库填充并且包含System.DBNull值,即使对象属性可为空,它们也不会转换为null。解决方案是将pro.SetValue()行更改为:pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : row[pro.Name]); - kooch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接