我正在尝试转换我的对象,它只有 1 个项目(类的 IList),该类包含 6 个属性 - 4 个字符串、1 个 anotherClass 的 IList 和 1 个字符串的 IList。 我正在使用下面的通用方法来转换:-
public static DataTable ToDataTable<T>(IList<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
//Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
此时 - dataTable.Rows.Add(values); 我有 4 和 5 属性的列表值,但是当我将它们添加到行时,它会显示文本(属性类型)行。虽然我需要 4 和 5 属性中的每一项都位于下一行。 例如:-
values[0] - "FirstString",
values[1] - "SecondString",
values[2] - "ThirdString",
values[3] - "FourthString",
values[4] - Count 2 - 100, 200 (IList<AnotherClass>()),
values [5] - Count 2 - "10W", "20W" (IList<string>)
我想要以下类型的输出:-
1String | 2String | 3String | 4String | Per | W |
:-----------|:------------:|:-----------:|:------------:|:---:|---:|
FirstString | SecondString | ThirdString | FourthString | 100 | 10W|
FirstString | SecondString | ThirdString | FourthString | 200 | 20W|
虽然我当前得到的输出是:-
1String | 2String | 3String | 4String | Per | W |
:-----------|:------------:|:-----------:|:------------:|:--------------:|--------------:|
FirstString | SecondString | ThirdString | FourthString | typeofproperty | typeofproperty|
我只想将对象的列表转换为 DataTable。
最佳答案
您的代码适用于 T
其中仅包含标量属性(即基本类型、字符串、日期等)。
当它处理集合或嵌套对象时,它会尝试将该对象或集合按原样存储在数据表的行中,因此结果与您预期的不一样。
要获得所需的输出,您需要首先展平列表项。
自 T
可以是任何东西,扁平化逻辑不能以通用方式实现。但是调用者可以为您执行此操作,因为他了解有关对象结构的所有内容。
有这些类型:
class Foo
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public IList<Bar> Bars { get; set; }
public IList<string> Strings { get; set; }
}
class Bar
{
public int A { get; set; }
}
您可以编写以下代码:
var items = new List<Foo>
{
new Foo
{
A = "FirstString",
B = "SecondString",
C = "ThirdString",
D = "FourthString",
Bars = new List<Bar>
{
new Bar { A = 100 },
new Bar { A = 200 }
},
Strings = new List<string>
{
"10W",
"20W"
}
}
};
var dataTable = items
.SelectMany(item => item.Bars.Zip(item.Strings, (bar, stringValue) => new
{
BarA = bar.A,
StringValue = stringValue
}),
(item, _) => new
{
item.A,
item.B,
item.C,
item.D,
_.BarA,
_.StringValue
})
.ToDataTable();
结果:
如您所见,将 SelectMany
内部的逻辑扁平化取决于什么T
是。比如说,如果有 3 个嵌套列表和 Bar
将包含public Boo { get; set; }
属性,该逻辑将改变以反射(reflect)新的对象结构。
附注我修改了ToDataTable
稍微定义一下,使其成为 IEnumerable<T>
的扩展方法:
static class ConversionExtensions
{
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
// your code here
}
}
关于c# - 如何将包含 IList<class> 的对象转换为 DataTable,该对象还包含 6 个属性 - 4 个字符串、1 个 IList<anotherclass>、1 个 IList<string> ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65246243/