首页 > 解决方案 > 如何转换对象包含 IList其中还包含 6 个属性 - 4 个字符串,1 个 IList, 1 个 IList到数据表?

问题描述

我正在尝试转换只有 1 个项目(类的 IList)的对象,该类包含 6 个属性 - 4 个字符串、1 个另一个类的 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。

以下是根据下面给出的解决方案的调试结果:- 在此处输入图像描述

@Dennis,仍然将属性类型作为列表类型属性的值。 在此处输入图像描述

标签: c#listobjectdatatable

解决方案


您的代码适用于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; }属性,则该逻辑将更改以反映新的对象结构。

PS我已经ToDataTable稍微修改了定义以使其扩展方法IEnumerable<T>

static class ConversionExtensions
{
    public static DataTable ToDataTable<T>(this IEnumerable<T> items)
    {
        // your code here
    }
}

推荐阅读