将数据表对象转换为列表 C#

Convert datatable object to list C#

我在 Whosebug 上找到了以下代码。但我不明白这段代码在做什么。谁能解释一下这段代码是如何工作的?

public static List<T> ToListof<T>(DataTable dt)
    {
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
        var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();
        var objectProperties = typeof(T).GetProperties(flags);
        var targetList = dt.AsEnumerable().Select(dataRow =>
        {
            var instanceOfT = Activator.CreateInstance<T>();

            foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
            {
                properties.SetValue(instanceOfT, dataRow[properties.Name], null);
            }
            return instanceOfT;
        }).ToList();

        return targetList;
    }

我特别想知道列数据在何处进行类型转换。我搜索了很多链接,但在任何地方都没有得到正确的答案。

它尝试在运行时动态地将数据表转换为类型 T 的对象列表。

var objectProperties = typeof(T).GetProperties(flags);

此行使用反射获取类型 T 的 public 属性列表。

var targetList = dt.AsEnumerable().Select(dataRow =>

此行将 DataTable 迭代为 IEnumerable,为每一行获取一个名为 dataRow 的实例。

var instanceOfT = Activator.CreateInstance<T>();

这将在循环内使用反射创建类型 T 的新实例。这意味着为每个数据行创建一个新的 T。

foreach (var properties in objectProperties.Where(properties => 
                  columnNames.Contains(properties.Name) 

这遍历了我们一开始得到的 T 的所有属性,这些属性也在 columnNames 中 - 这意味着有一列具有它们的值

  && dataRow[properties.Name] != DBNull.Value))

条件的后半部分确保该列具有值且不为 NULL。

  properties.SetValue(instanceOfT, dataRow[properties.Name], null);

这再次使用反射将数据行中的值设置到 T 的 属性 中。

).ToList();

这需要从 Select 语句返回的所有项目和 returns 它们的列表。

如果您知道反射的工作原理,代码不是最简洁的,但变量的名称非常好且清晰。至于你的第二个问题 - 没有转换,因为这段代码假定 DataRow 中的值类型与 属性 的类型相匹配。如果没有,将抛出异常。

详细信息:

const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

这将结合 public 和实例标志,以便仅搜索 Public 个非静态方法。

 var columnNames = dt.Columns.Cast<DataColumn>()
    .Select(c => c.ColumnName)
    .ToList();

这将列出数据中的所有列名称 table

var objectProperties = typeof(T).GetProperties(flags);

获取通用参数的类型并将列出所有 public、非静态属性

dt.AsEnumerable().Select

为 DataTable 中的每个数据行创建一个 IEnumerable

var instanceOfT = Activator.CreateInstance<T>();

这会像您使用的那样创建一个新实例 new

 foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
 {
     properties.SetValue(instanceOfT, dataRow[properties.Name], null);
 }

这将遍历 T 的所有属性,这些属性也包含在数据中table而不是 null(例如,数据库中的 DbNull)

然后调用 SetValue。由于 dataRow 已经 return 存储在数据库中的值,因此没有强制转换。这仅在 属性 和数据库中的类型为 "the same" 时才有效。作为字符串的 NVarchar。