【问题标题】:How to Convert DataTable to Generic List in C# [duplicate]如何在 C# 中将 DataTable 转换为通用列表 [重复]
【发布时间】:2016-12-16 08:54:08
【问题描述】:

我需要将 C# DataTable 转换为通用集合列表

DataTable Columns Respectively

 1. EmpId  (this is Int DataType)
 2. EmpName   (this is varchar DataType)
 3. EmpAddress  (this is varchar DataType)
 4. EmpPhone  (this is varchar DataType)
 5. Status   (this is Boolean DataType)
 6. EmpRelationKey (this is int DataType)

所以我的 DataTable 包含上述字段的值。在这里我需要将此值分配到我的列表中

我的列表变量分别

class Employee
{
protected int EmpId  ;
protected string EmpName =String.Empty;
protected string EmpAddress  = String.Empty;
protected string EmpPhone  = String.Empty;
protected bool Status ;
protected int EmpRelationKey ;
}

Declaring List
List<Employee> Emp= new List<Employee>

所以现在我需要将 DataTable 值分配给这个列表。代码应该很专业。

这个方法我试过了

List<Employee>employees = new List<Employee>();  

foreach (DataRow row in dt.Rows)  
{  
   employees.Add(new Employee  
   {  
   EmpId  = Convert.ToInt32(row["EmpId"]), 
   EmpName = row["EmpName"].ToString() ,
   EmpAddress =   row["EmpName"].ToString(),
   Emphone =   row["EmpPhone"].ToString(),
   Status = Convert.toBoolean(row["Status"])
   });  
}   

但我不想提及列名,有没有其他方法可以在不提及 DataTable 中的每个列名的情况下分配值

【问题讨论】:

  • 反思............
  • 如何使用或应用于此
  • 你能帮我解决这个问题并发布代码以供参考
  • 但我的列表是用户定义类型

标签: c# asp.net


【解决方案1】:
using System.Reflection;

那么,

public static List<T> BindList<T>(DataTable dt)
{
    // Example 1:
    // Get private fields + non properties
    //var fields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

    // Example 2: Your case
    // Get all public fields
    var fields = typeof(T).GetFields();

    List<T> lst = new List<T>();

    foreach (DataRow dr in dt.Rows)
    {
        // Create the object of T
        var ob = Activator.CreateInstance<T>();

        foreach (var fieldInfo in fields)
        {
            foreach (DataColumn dc in dt.Columns)
            {
                // Matching the columns with fields
                if (fieldInfo.Name == dc.ColumnName)
                {
                    // Get the value from the datatable cell
                    object value = dr[dc.ColumnName];

                    // Set the value into the object
                    fieldInfo.SetValue(ob, value);
                    break;
                }
            }
        }

        lst.Add(ob);
    }

    return lst;
}

使用示例:

DataTable dt1 = SqlHelper.GetTable("select * from employee;");
List<Employee> employees = BindList<Employee>(dt1);

DataTable dt2 = SqlHelper.GetTable("select * from membership;");
List<Membership> lstMembership = BindList<Membership>(dt2);

DataTable dt3 = SqlHelper.GetTable("select * from car order by name;");
List<Car> lstCar = BindList<Car>(dt3);

======================

加长版

以上示例假设 DataTable 中保存的数据与 Class 对象 的字段具有相同的数据类型

如果数据与您的类对象的字段不同怎么办?

null

因此,您可能需要扩展该方法以防万一两种数据类型不相同。

public static List<T> BindList<T>(DataTable dt)
{
    // Example 1:
    // Get private fields + non properties
    //var fields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

    // Example 2: Your case
    // Get all public fields
    var fields = typeof(T).GetFields();

    List<T> lst = new List<T>();

    foreach (DataRow dr in dt.Rows)
    {
        // Create the object of T
        var ob = Activator.CreateInstance<T>();

        foreach (var fieldInfo in fields)
        {
            foreach (DataColumn dc in dt.Columns)
            {
                // Matching the columns with fields
                if (fieldInfo.Name == dc.ColumnName)
                {
                    Type type = fieldInfo.FieldType;

                    // Get the value from the datatable cell
                    object value = GetValue(dr[dc.ColumnName], type);

                    // Set the value into the object
                    fieldInfo.SetValue(ob, value);
                    break;
                }
            }
        }

        lst.Add(ob);
    }

    return lst;
}

static object GetValue(object ob, Type targetType)
{
    if (targetType == null)
    {
        return null;
    }
    else if (targetType == typeof(String))
    {
        return ob + "";
    }
    else if (targetType == typeof(int))
    {
        int i = 0;
        int.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(short))
    {
        short i = 0;
        short.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(long))
    {
        long i = 0;
        long.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(ushort))
    {
        ushort i = 0;
        ushort.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(uint))
    {
        uint i = 0;
        uint.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(ulong))
    {
        ulong i = 0;
        ulong.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(double))
    {
        double i = 0;
        double.TryParse(ob + "", out i);
        return i;
    }
    else if (targetType == typeof(DateTime))
    {
        // do the parsing here...
    }
    else if (targetType == typeof(bool))
    {
        // do the parsing here...
    }
    else if (targetType == typeof(decimal))
    {
        // do the parsing here...
    }
    else if (targetType == typeof(float))
    {
        // do the parsing here...
    }
    else if (targetType == typeof(byte))
    {
        // do the parsing here...
    }
    else if (targetType == typeof(sbyte))
    {
        // do the parsing here...
    }
    else if........
    ..................

    return ob;
}

【讨论】:

  • 这个工作正常。
  • DataTable dt1 = SqlHelper.GetTable("select * from employee;"); List 员工 = BindList(dt);
  • @kselva 几个月前,我问过同样的问题。许多人向我分享了他们的知识。现在,轮到我把答案传递给其他人了:)
  • 我尝试了扩展实例,使用var fields = typeof(T).GetFields();时没有返回字段。因此,var fields = typeof(T).GetFields(); 可能不适用于自定义类。经过一番挖掘,我发现使用var fields = typeof(T).GetRuntimeFields(); 我的解决方案不适合一个评论,所以下一个评论是解决方案。
  • 使用typeof(T).GetRuntimeFields(),您将获得如下字段名称:k__BackingField,其中的字段名称与 fieldInfo.Name == dc.ColumnName 不匹配,其中 dc.ColumnName 是“EmpName”。相反,您需要转换每个 dc.ColumnName 以匹配 fieldInfo.Name。我使用string fnTemplate = "&lt;{0}&gt;k__BackingField";的字符串模板,然后使用tFN = string.Format(fnTemplate, dc.ColumnName).ToLower();,然后比较为if (fieldInfo.Name.ToLower() == tFN)
【解决方案2】:

你可以试试这样的:

List<Employee> listObject = dTable.AsEnumerable()
                                  .Select(x => new Employee()
                                  {
                                    EmpId = x.Field<int>("EmpId"),
                                    EmpName = x.Field<string>("EmpName"),
                                    EmpAddress = x.Field<string>("EmpName"),
                                    EmpPhone = x.Field<string>("EmpPhone"),
                                    Status = x.Field<bool>("Status"),
                                    EmpRelationKey = x.Field<int>("EmpRelationKey")
                                  }).ToList();

【讨论】:

  • “但我不想提及列名”
  • 改用它的列索引
  • 是的,@sujithkarivelil,使用列索引也不是动态的,这就是 kselva 正在寻求的......
【解决方案3】:

使用 LinQ 你可以做到,

  List<DataRow> list = Datatablle.AsEnumerable().ToList();

更新答案。创建 Helper 类以将 Datatable 转换为 List

public static class Helper
{

    public static List<T> ConvertDataTableToList<T>(this DataTable table) where T : class, new()
    {
        try
        {
            List<T> list = new List<T>();

            foreach (var row in table.AsEnumerable())
            {
                T obj = new T();

                foreach (var prop in obj.GetType().GetProperties())
                {
                    try
                    {
                        PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
                        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
                    }
                    catch
                    {
                        continue;
                    }
                }

                list.Add(obj);
            }

            return list;
        }
        catch
        {
            return null;
        }
    }
}

那么,

DataTable dtDatatable = GetEmployee();
List<Employee> employeeList = dtDatatable.ConvertDataTableToList<Employee>();

【讨论】:

  • 我需要将数据表值直接分配给这个列表
  • List 员工 = new List();
  • 请检查更新的答案。
  • 是的,是的,我会更新答案,刚才我正在申请我的代码
  • 我在这一行得到错误 dtDatatable.ConvertDataTableToList();
【解决方案4】:

正如评论中提到的,每当您在DataTable 结构中进行任何更改时,这些更改也必须在Class 中完成,如果您更改Class,则将这些更改与DataTable 结构同步。

List<Employee>employees = new List<Employee>();  

foreach (DataRow row in dt.Rows)  
{  
    Employee emp= new Employee();

    PropertyInfo[] properties = typeof(Employee).GetProperties();
    for (int i = 0; i < properties.Length; i++)
    {
        property.SetValue(emp, Convert.ChangeType(row[i], property.GetType()));
    }
}

别忘了using System.Reflection;

【讨论】:

  • 请记住,如果您更改类的列名或属性 - 此代码将产生不正确的结果
  • 什么是该 property.setValue 的代表,该行发生错误
  • 's'的资本不小。什么是错误
猜你喜欢
  • 1970-01-01
  • 2018-11-20
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多