C# 将通用嵌套列表转换为Datatable
我一直在使用以下代码将泛型C# 将通用嵌套列表转换为Datatable,c#,list,generics,datatable,C#,List,Generics,Datatable,我一直在使用以下代码将泛型列表转换为数据表: public static DataTable ToDataTable<T>(this IList<T> data) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); DataTable table = new DataTable();
列表
转换为数据表
:
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooA | barA |
| fooA | barB |
要生成数据表
:
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooA | barA |
| fooA | barB |
原始代码解释了foo
中的许多属性,bar
也有此要求
到目前为止,我已经能够检索到bar
的属性,但是当List
为空时,我无法找出如何填充Datatable
。我没有很多编写泛型方法的经验,所以我很抱歉不能提供我的很多工作
其他示例:
名单
名单
课程:
foo
class foo
{
public string GenericProperty;
public List<bar> GenericNestedList;
public foo(string GenericProperty, List<bar> GenericNestedList)
{
this.GenericProperty = GenericProperty;
this.GenericNestedList = GenericNestedList;
}
}
只是一个快速解决方案:
public DataTable CreateNestedDataTable<TOuter, TInner>(IEnumerable<TOuter> list, string innerListPropertyName)
{
PropertyInfo[] outerProperties = typeof(TOuter).GetProperties().Where(pi => pi.Name != innerListPropertyName).ToArray();
PropertyInfo[] innerProperties = typeof(TInner).GetProperties();
MethodInfo innerListGetter = typeof(TOuter).GetProperty(innerListPropertyName).GetMethod;
// set up columns
DataTable table = new DataTable();
foreach (PropertyInfo pi in outerProperties)
table.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
foreach (PropertyInfo pi in innerProperties)
table.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
// iterate through outer items
foreach (TOuter outerItem in list)
{
var innerList = innerListGetter.Invoke(outerItem, null) as IEnumerable<TInner>;
if (innerList == null || innerList.Count() == 0)
{
// outer item has no inner items
DataRow row = table.NewRow();
foreach (PropertyInfo pi in outerProperties)
row[pi.Name] = pi.GetValue(outerItem) ?? DBNull.Value;
table.Rows.Add(row);
}
else
{
// iterate through inner items
foreach (object innerItem in innerList)
{
DataRow row = table.NewRow();
foreach (PropertyInfo pi in outerProperties)
row[pi.Name] = pi.GetValue(outerItem) ?? DBNull.Value;
foreach (PropertyInfo pi in innerProperties)
row[pi.Name] = pi.GetValue(innerItem) ?? DBNull.Value;
table.Rows.Add(row);
}
}
}
return table;
}
嗨@poke,谢谢你的回复。上面的代码有两个问题:每个
行[pi.Name]=pi.GetValue(outerItem)??DBNull.Value
正在生成错误“方法“GetValue”的无重载包含1个参数。typeof(TOuter).GetProperty(innerListPropertyName).GetMethod;
也正在生成错误“'System.Reflection.PropertyInfo'不包含“GetMethod”的定义。。。“@Chawin您的目标.NET framework版本是什么?PropertyInfo.GetValue
和PropertyInfo.GetMethod
都是在.NET 4.5中引入的。真是不同寻常,我在Visual C#2010 express上运行了4.5.51209版。我会仔细研究一下,看看是什么导致了这个问题。@Chawin我已经添加了一些说明,说明了旧版本应该替换什么。我不知道为什么会这样,我当然不是故意的!标记回已接受:)
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooC | barC |
| fooC | barD |
| fooD | barE |
| fooD | barF |
class foo
{
public string GenericProperty;
public List<bar> GenericNestedList;
public foo(string GenericProperty, List<bar> GenericNestedList)
{
this.GenericProperty = GenericProperty;
this.GenericNestedList = GenericNestedList;
}
}
class bar
{
public string GenericNestedProperty;
public bar(string GenericNestedProperty)
{
this.GenericNestedProperty = GenericNestedProperty;
}
}
public DataTable CreateNestedDataTable<TOuter, TInner>(IEnumerable<TOuter> list, string innerListPropertyName)
{
PropertyInfo[] outerProperties = typeof(TOuter).GetProperties().Where(pi => pi.Name != innerListPropertyName).ToArray();
PropertyInfo[] innerProperties = typeof(TInner).GetProperties();
MethodInfo innerListGetter = typeof(TOuter).GetProperty(innerListPropertyName).GetMethod;
// set up columns
DataTable table = new DataTable();
foreach (PropertyInfo pi in outerProperties)
table.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
foreach (PropertyInfo pi in innerProperties)
table.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
// iterate through outer items
foreach (TOuter outerItem in list)
{
var innerList = innerListGetter.Invoke(outerItem, null) as IEnumerable<TInner>;
if (innerList == null || innerList.Count() == 0)
{
// outer item has no inner items
DataRow row = table.NewRow();
foreach (PropertyInfo pi in outerProperties)
row[pi.Name] = pi.GetValue(outerItem) ?? DBNull.Value;
table.Rows.Add(row);
}
else
{
// iterate through inner items
foreach (object innerItem in innerList)
{
DataRow row = table.NewRow();
foreach (PropertyInfo pi in outerProperties)
row[pi.Name] = pi.GetValue(outerItem) ?? DBNull.Value;
foreach (PropertyInfo pi in innerProperties)
row[pi.Name] = pi.GetValue(innerItem) ?? DBNull.Value;
table.Rows.Add(row);
}
}
}
return table;
}
var table = CreateNestedDataTable<foo, bar>(GenericList, "GenericNestedList");
// before
typeof(TOuter).GetProperty(innerListPropertyName).GetMethod;
// after
typeof(TOuter).GetProperty(innerListPropertyName).GetGetMethod(true);
// for each row assignment
// before
row[pi.Name] = pi.GetValue(item) ?? DBNull.Value;
// after
row[pi.Name] = pi.GetValue(item, null) ?? DBNull.Value;