【问题标题】:Convert Generic Nested List to Datatable将通用嵌套列表转换为数据表
【发布时间】:2015-11-20 10:00:38
【问题描述】:

Continuation from "Convert generic List/Enumerable to 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;
    }

但是,我现在有一个列表List&lt;foo&gt;,其中foo 包含属性List&lt;bar&gt;(其中List&lt;bar&gt; 可以包含零值)。

问题:

我想转换一个泛型List&lt;foo&gt;,其中包含另一个泛型嵌套List&lt;bar&gt;,例如:

        List<bar> GenericNestedList = new List<bar>{ new bar("barA"), new bar("barB") };
        List<foo> GenericList = new List<foo> { new foo("fooA", GenericNestedList) };

生成DataTable

| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
|      fooA       |         barA          |
|      fooA       |         barB          |

原代码占foo内的很多属性,bar也会有这个要求。

到目前为止,我已经能够检索bar 的属性,但是当List&lt;bar&gt; 为空时,我无法弄清楚如何填充Datatable。我没有太多编写泛型方法的经验,所以我很抱歉不能提供我的很多工作。

其他示例:

列表

List<foo> GenericList = new List<foo> { new foo("fooB", new List<bar>()) };

数据表

| GenericProperty | GenericNestedProperty |
|-----------------|-----------------------|
|      fooB       |                       |

列表

        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) };

数据表

| 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;
    }
}

【问题讨论】:

    标签: c# list generics datatable


    【解决方案1】:

    只是一个快速的解决方案:

    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");
    

    用你的例子测试,它产生了预期的结果:


    以上代码使用 .NET 4.5 引入的 PropertyInfo.GetMethodPropertyInfo.GetValue。对于 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;
    

    【讨论】:

    • 嗨@poke,感谢您的回复。上面的代码有两个问题:每个row[pi.Name] = pi.GetValue(outerItem) ?? DBNull.Value; 都在生成错误“方法'GetValue' 没有重载需要1 个参数。typeof(TOuter).GetProperty(innerListPropertyName).GetMethod; 也生成了“'System.Reflection.PropertyInfo' 没有的错误包含 'GetMethod' 的定义..."
    • @Chawin 您的目标是什么 .NET 框架版本? PropertyInfo.GetValuePropertyInfo.GetMethod 都是在 .NET 4.5 中引入的。
    • 多么不寻常,我在 Visual C# 2010 express 上运行版本 4.5.51209。我会戳一下,看看可能是什么导致了这个问题。
    • @Chawin 我已经添加了旧版本替换的说明。那应该可以正常工作。
    • 我不知道为什么会这样,我当然不是故意的!标记回接受:)
    猜你喜欢
    • 1970-01-01
    • 2020-06-22
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 2013-02-18
    相关资源
    最近更新 更多