最近在做一些单元测试,因为数据库里面的数据比较乱,不适合直接做单元测试的数据源,又不想自己再往里面插数据,把已经很混乱得数据库搞得更混乱,就直接写了从List<T>直接转换成对应的DataTable的类,然后在把这个DataTable再注入到单元测试里面。于是就有了这么一段代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public static DataTable ToDataTable<T>(this IEnumerable<T> list)
where T : class
{
var props = GetProperties<T>().ToList();
DataTable dt = new DataTable();
foreach (var p in props)
{
Type t = p.Value.PropertyType;
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
{
t = t.GetGenericArguments()[0];
}
dt.Columns.Add(p.Key, t);
}
foreach (var item in list)
{
var row = dt.NewRow();
foreach (var p in props)
{
row[p.Key] = p.Value.GetValue(item, null) ?? DBNull.Value;
}
dt.Rows.Add(row);
}
return dt;
}
这里有一个GetProperies的方法,根据大家不同的T实体的习惯,需要对应的实现方式,因为我的实体本身是通过自定义的DbColumnAttribute来指定的,所以实现如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
private static IEnumerable<KeyValuePair<string, PropertyInfo>> GetProperties<T>()
{
foreach (var prop in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (prop.GetIndexParameters().Length > 0)
continue;
var setMethod = prop.GetSetMethod(false);
if (setMethod == null)
continue;
var attr = Attribute.GetCustomAttribute(prop, typeof(DbColumnAttribute), true);
if (attr == null)
continue;
yield return new KeyValuePair<string, PropertyInfo>(((DbColumnAttribute)attr).ColumnName ?? prop.Name, prop);
}