[英]Convert Generic Nested List to Datatable
Continuation from "Convert generic List/Enumerable to DataTable?" 继续“将通用列表/枚举转换为数据表?”
I've been using the following code to covert a generic List<T>
into a DataTable
:我一直在使用以下代码将通用
List<T>
转换为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;
}
However, I now have a list List<foo>
where foo
contains a property List<bar>
(where List<bar>
can contain zero values).但是,我现在有一个列表
List<foo>
,其中foo
包含一个属性List<bar>
(其中List<bar>
可以包含零值)。
Question:题:
I want to convert a generic List<foo>
containing another generic nested List<bar>
such as :我想转换包含另一个通用嵌套
List<bar>
的通用List<foo>
,例如:
List<bar> GenericNestedList = new List<bar>{ new bar("barA"), new bar("barB") };
List<foo> GenericList = new List<foo> { new foo("fooA", GenericNestedList) };
To result in a DataTable
:产生一个
DataTable
:
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooA | barA |
| fooA | barB |
The original code accounts for many properties within foo
, bar
would also have this requirement.原始代码在
foo
考虑了许多属性, bar
也会有这个要求。
So far I've been able to retrieve the properties of bar
, however I've been unable to figure out how to populate the Datatable
when List<bar>
is empty.到目前为止,我已经能够检索
bar
的属性,但是我一直无法弄清楚如何在List<bar>
为空时填充Datatable
。 I don't have a lot of experience writing generic methods, so my apologies for not being able to provide a lot of my workings.我没有很多编写泛型方法的经验,所以我很抱歉不能提供很多我的工作。
Other Examples:其他例子:
List列表
List<foo> GenericList = new List<foo> { new foo("fooB", new List<bar>()) };
Datatable数据表
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooB | |
List列表
List<bar> GenericNestedListA = new List<bar>{ new bar("barC"), new bar("barD") };
List<bar> GenericNestedListB = new List<bar> { new bar("barE"), new bar("barF") };
List<foo> GenericList = new List<foo> { new foo("fooC", GenericNestedListA),
new foo("fooD", GenericNestedListB) };
Datatable数据表
| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
| fooC | barC |
| fooC | barD |
| fooD | barE |
| fooD | barF |
Classes:课程:
foo富
class foo
{
public string GenericProperty;
public List<bar> GenericNestedList;
public foo(string GenericProperty, List<bar> GenericNestedList)
{
this.GenericProperty = GenericProperty;
this.GenericNestedList = GenericNestedList;
}
}
bar酒吧
class bar
{
public string GenericNestedProperty;
public bar(string GenericNestedProperty)
{
this.GenericNestedProperty = GenericNestedProperty;
}
}
Just a quick solution:只是一个快速的解决方案:
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;
}
One could probably expand this even further, so it could work with multiple nested lists, or automatically recognize the properties that are nested lists.人们可能会进一步扩展这一点,因此它可以处理多个嵌套列表,或者自动识别嵌套列表的属性。 But I kept it simple here.
但我在这里保持简单。
It's used like this:它是这样使用的:
var table = CreateNestedDataTable<foo, bar>(GenericList, "GenericNestedList");
Tested with your examples, it produces the desired results:用你的例子测试,它产生了预期的结果:
Above code uses PropertyInfo.GetMethod
and PropertyInfo.GetValue
which were introduced with .NET 4.5.上面的代码使用了 .NET 4.5 引入的
PropertyInfo.GetMethod
和PropertyInfo.GetValue
。 For 4.0, make the following replacements:对于 4.0,进行以下替换:
// 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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.