Convert generic List/Enumerable to DataTable?

后端 未结 27 2157
臣服心动
臣服心动 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:52
      using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using System.ComponentModel;
    
    public partial class Default3 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            DataTable dt = new DataTable();
            dt = lstEmployee.ConvertToDataTable();
        }
        public static DataTable ConvertToDataTable<T>(IList<T> list) where T : class
        {
            try
            {
                DataTable table = CreateDataTable<T>();
                Type objType = typeof(T);
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(objType);
                foreach (T item in list)
                {
                    DataRow row = table.NewRow();
                    foreach (PropertyDescriptor property in properties)
                    {
                        if (!CanUseType(property.PropertyType)) continue;
                        row[property.Name] = property.GetValue(item) ?? DBNull.Value;
                    }
    
                    table.Rows.Add(row);
                }
                return table;
            }
            catch (DataException ex)
            {
                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
    
        }
        private static DataTable CreateDataTable<T>() where T : class
        {
            Type objType = typeof(T);
            DataTable table = new DataTable(objType.Name);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(objType);
            foreach (PropertyDescriptor property in properties)
            {
                Type propertyType = property.PropertyType;
                if (!CanUseType(propertyType)) continue;
    
                //nullables must use underlying types
                if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                //enums also need special treatment
                if (propertyType.IsEnum)
                    propertyType = Enum.GetUnderlyingType(propertyType);
                table.Columns.Add(property.Name, propertyType);
            }
            return table;
        }
    
    
        private static bool CanUseType(Type propertyType)
        {
            //only strings and value types
            if (propertyType.IsArray) return false;
            if (!propertyType.IsValueType && propertyType != typeof(string)) return false;
            return true;
        }
    }
    
    0 讨论(0)
  • 2020-11-21 23:53

    To Convert Generic list into DataTable

    using Newtonsoft.Json;

    public DataTable GenericToDataTable(IList<T> list)
    {
        var json = JsonConvert.SerializeObject(list);
        DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
        return dt;
    }
    
    0 讨论(0)
  • 2020-11-21 23:54

    This is the simple Console Application to convert List to Datatable.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.ComponentModel;
    
    namespace ConvertListToDataTable
    {
        public static class Program
        {
            public static void Main(string[] args)
            {
                List<MyObject> list = new List<MyObject>();
                for (int i = 0; i < 5; i++)
                {
                    list.Add(new MyObject { Sno = i, Name = i.ToString() + "-KarthiK", Dat = DateTime.Now.AddSeconds(i) });
                }
    
                DataTable dt = ConvertListToDataTable(list);
                foreach (DataRow row in dt.Rows)
                {
                    Console.WriteLine();
                    for (int x = 0; x < dt.Columns.Count; x++)
                    {
                        Console.Write(row[x].ToString() + " ");
                    }
                }
                Console.ReadLine();
            }
    
            public class MyObject
            {
                public int Sno { get; set; }
                public string Name { get; set; }
                public DateTime Dat { get; set; }
            }
    
            public static DataTable ConvertListToDataTable<T>(this List<T> iList)
            {
                DataTable dataTable = new DataTable();
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
                for (int i = 0; i < props.Count; i++)
                {
                    PropertyDescriptor propertyDescriptor = props[i];
                    Type type = propertyDescriptor.PropertyType;
    
                    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                        type = Nullable.GetUnderlyingType(type);
    
                    dataTable.Columns.Add(propertyDescriptor.Name, type);
                }
                object[] values = new object[props.Count];
                foreach (T iListItem in iList)
                {
                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = props[i].GetValue(iListItem);
                    }
                    dataTable.Rows.Add(values);
                }
                return dataTable;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-21 23:55

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

    IEnumerable<SomeType> 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<SomeType> 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<T>(this IList<T> 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<MyData> 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<MyData> foos = new List<MyData>();
            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        
        }
    }
    
    0 讨论(0)
  • 2020-11-21 23:56

    I also had to come up with an alternate solution, as none of the options listed here worked in my case. I was using an IEnumerable which returned an IEnumerable and the properties couldn't be enumerated. This did the trick:

    // remove "this" if not on C# 3.0 / .NET 3.5
    public static DataTable ConvertToDataTable<T>(this IEnumerable<T> data)
    {
        List<IDataRecord> list = data.Cast<IDataRecord>().ToList();
    
        PropertyDescriptorCollection props = null;
        DataTable table = new DataTable();
        if (list != null && list.Count > 0)
        {
            props = TypeDescriptor.GetProperties(list[0]);
            for (int i = 0; i < props.Count; i++)
            {
                PropertyDescriptor prop = props[i];
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
        }
        if (props != null)
        {
            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) ?? DBNull.Value;
                }
                table.Rows.Add(values);
            }
        }
        return table;
    }
    
    0 讨论(0)
  • 2020-11-21 23:56
     Dim counties As New List(Of County)
     Dim dtCounties As DataTable
     dtCounties = _combinedRefRepository.Get_Counties()
     If dtCounties.Rows.Count <> 0 Then
        For Each row As DataRow In dtCounties.Rows
          Dim county As New County
          county.CountyId = row.Item(0).ToString()
          county.CountyName = row.Item(1).ToString().ToUpper()
          counties.Add(county)
        Next
        dtCounties.Dispose()
     End If
    
    0 讨论(0)
提交回复
热议问题