我在 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;
}
我特别想知道列的数据在哪里进行类型转换。我搜索了很多链接,但在任何地方都没有得到正确的答案。
它尝试在运行时动态地将数据表转换为 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 中的值的类型与属性的类型匹配。如果不存在,将会抛出异常。
详细:
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。