C# how to convert IEnumerable anonymous lists into data table

前端 未结 2 1407
别跟我提以往
别跟我提以往 2021-01-15 11:12

Many solutions are available that convert lists to DataTable that use reflection, and that would work for converting anonymous types. However, it there are

2条回答
  •  日久生厌
    2021-01-15 11:22

    It would absolutely be better to do this using proper named POCO/DTO/etc classes, but it can still be done. The cost of reflection can be removed by using meta-programming, ideally by using a pre-rolled library such as FastMember, as shown below.

    Note that the use of anonymous types has forced the use of IList here (rather than IList or List etc). The use of a generic version would be preferable, using named types. This would allow a few changes - in particular, itemType would be typeof(T), and it would be possible to create the correct columns even for an empty table. Perhaps more importantly, it would enforce that the list is homogeneous, rather than having to make an assumption about that.

    using FastMember;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    static class Program
    {
        static void Main()
        {
            var list = GetList();
            var table = ToTable(list);
        }
        static DataTable ToTable(IList source)
        {
            if (source == null) throw new ArgumentNullException();
            var table = new DataTable();
            if (source.Count == 0) return table;
    
            // blatently assume the list is homogeneous
            Type itemType = source[0].GetType();
            table.TableName = itemType.Name;
            List names = new List();
            foreach (var prop in itemType.GetProperties())
            {
                if (prop.CanRead && prop.GetIndexParameters().Length == 0)
                {
                    names.Add(prop.Name);
                    table.Columns.Add(prop.Name, prop.PropertyType);
                }
            }
            names.TrimExcess();
    
            var accessor = TypeAccessor.Create(itemType);
            object[] values = new object[names.Count];
            foreach (var row in source)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = accessor[row, names[i]];
                }
                table.Rows.Add(values);
            }
            return table;
        }
        static IList GetList()
        {
            return new[] {
                new { foo = "abc", bar = 123},
                new { foo = "def", bar = 456},
                new { foo = "ghi", bar = 789},
            };
        }
    }
    

提交回复
热议问题