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

问题描述 投票:0回答:2

我在 stackoverflow 上找到了以下代码。但我不明白这段代码的根本作用。谁能解释一下这段代码是如何工作的?

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;
    }

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

c# asp.net c#-4.0
2个回答
1
投票

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

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

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

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

此行将 DataTable 作为 IEnumerable 进行迭代,为每行获取一个名为

dataRow
的实例。

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

这会在循环内使用反射创建类型 T 的新实例。这意味着为每个 dataRow 创建一个新的 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 语句返回的所有项目并从中返回一个列表。

代码不是最简洁的,但是如果您知道反射是如何工作的,那么变量的命名非常好且清晰。至于你的第二个问题 - 没有强制转换,因为此代码假设 DataRow 中的值的类型与属性的类型匹配。如果不存在,将会抛出异常。


1
投票

详细:

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

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

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

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

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

获取泛型参数的类型,并将列出所有公共、非静态属性

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 的所有属性,该属性也包含在数据表中且不为空(例如,来自数据库的 DbNull)

然后调用SetValue。由于 dataRow 已经返回存储在数据库中的值,因此不需要强制转换。仅当属性和数据库中的类型“相同”时,这才有效。作为字符串的 NVarchar。

© www.soinside.com 2019 - 2024. All rights reserved.