Convert generic List/Enumerable to DataTable?

后端 未结 27 2155
臣服心动
臣服心动 2020-11-21 23:20

I have few methods that returns different Generic Lists.

Exists in .net any class static method or whatever to convert any list into a datatable? The only thing tha

27条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-11-21 23:55

    Here's a nice 2013 update using FastMember from NuGet:

    IEnumerable data = ...
    DataTable table = new DataTable();
    using(var reader = ObjectReader.Create(data)) {
        table.Load(reader);
    }
    

    This uses FastMember's meta-programming API for maximum performance. If you want to restrict it to particular members (or enforce the order), then you can do that too:

    IEnumerable data = ...
    DataTable table = new DataTable();
    using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
        table.Load(reader);
    }
    

    Editor's Dis/claimer: FastMember is a Marc Gravell project. It's gold and full-on flies!


    Yes, this is pretty much the exact opposite of this one; reflection would suffice - or if you need quicker, HyperDescriptor in 2.0, or maybe Expression in 3.5. Actually, HyperDescriptor should be more than adequate.

    For example:

    // remove "this" if not on C# 3.0 / .NET 3.5
    public static DataTable ToDataTable(this IList data)
    {
        PropertyDescriptorCollection props =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        for(int i = 0 ; i < props.Count ; i++)
        {
            PropertyDescriptor prop = props[i];
            table.Columns.Add(prop.Name, prop.PropertyType);
        }
        object[] values = new object[props.Count];
        foreach (T item in data)
        {
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = props[i].GetValue(item);
            }
            table.Rows.Add(values);
        }
        return table;        
    }
    

    Now with one line you can make this many many times faster than reflection (by enabling HyperDescriptor for the object-type T).


    Edit re performance query; here's a test rig with results:

    Vanilla 27179
    Hyper   6997
    

    I suspect that the bottleneck has shifted from member-access to DataTable performance... I doubt you'll improve much on that...

    Code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    public class MyData
    {
        public int A { get; set; }
        public string B { get; set; }
        public DateTime C { get; set; }
        public decimal D { get; set; }
        public string E { get; set; }
        public int F { get; set; }
    }
    
    static class Program
    {
        static void RunTest(List data, string caption)
        {
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            GC.WaitForFullGCComplete();
            Stopwatch watch = Stopwatch.StartNew();
            for (int i = 0; i < 500; i++)
            {
                data.ToDataTable();
            }
            watch.Stop();
            Console.WriteLine(caption + "\t" + watch.ElapsedMilliseconds);
        }
        static void Main()
        {
            List foos = new List();
            for (int i = 0 ; i < 5000 ; i++ ){
                foos.Add(new MyData
                { // just gibberish...
                    A = i,
                    B = i.ToString(),
                    C = DateTime.Now.AddSeconds(i),
                    D = i,
                    E = "hello",
                    F = i * 2
                });
            }
            RunTest(foos, "Vanilla");
            Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(
                typeof(MyData));
            RunTest(foos, "Hyper");
            Console.ReadLine(); // return to exit        
        }
    }
    

提交回复
热议问题