Использование Reflection для создания DataTable из класса?

Я только что узнал о Generics, и мне интересно, могу ли я использовать его для динамического создания datatables из моих классов.

Или, может быть, здесь не хватает смысла. Вот мой код, что я пытаюсь сделать, это создать datatable из моего существующего класса и заполнить его. Однако я застрял в мыслительном процессе.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data;

namespace Generics
{
    public class Dog
    {
        public string Breed { get; set; }
        public string Name { get; set; }
        public int legs { get; set; }
        public bool tail { get; set; }
    }

    class Program
    {
        public static DataTable CreateDataTable(Type animaltype)
        {
            DataTable return_Datatable = new DataTable();
            foreach (PropertyInfo info in animaltype.GetProperties())
            {
                return_Datatable.Columns.Add(new DataColumn(info.Name, info.PropertyType));
            }
            return return_Datatable;
        }

        static void Main(string[] args)
        {
            Dog Killer = new Dog();
            Killer.Breed = "Maltese Poodle";
            Killer.legs = 3;
            Killer.tail = false;
            Killer.Name = "Killer";

            DataTable dogTable = new DataTable();
            dogTable = CreateDataTable(Dog);
//How do I continue from here?


        }      
    }
}    

Теперь в точке DataTable укажите ошибки. Кроме того, будучи новым для размышлений и Generics, как я действительно заполню данные классом Killer?

Ответы

Ответ 1

Создавая все предыдущие ответы, вот версия, которая создает DataTable из любой коллекции:

public static DataTable CreateDataTable<T>(IEnumerable<T> list)
{
    Type type = typeof(T);
    var properties = type.GetProperties();      

    DataTable dataTable = new DataTable();
    foreach (PropertyInfo info in properties)
    {
        dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
    }

    foreach (T entity in list)
    {
        object[] values = new object[properties.Length];
        for (int i = 0; i < properties.Length; i++)
        {
            values[i] = properties[i].GetValue(entity);
        }

        dataTable.Rows.Add(values);
    }

    return dataTable;
}

Ответ 2

моя любимая домашняя функция. он создает и заполняет все одновременно. бросить любой объект.

 public static DataTable ObjectToData(object o)
 {
    DataTable dt = new DataTable("OutputData");

    DataRow dr = dt.NewRow();
    dt.Rows.Add(dr);

    o.GetType().GetProperties().ToList().ForEach(f =>
    {
        try
        {
            f.GetValue(o, null);
            dt.Columns.Add(f.Name, f.PropertyType);
            dt.Rows[0][f.Name] = f.GetValue(o, null);
        }
        catch { }
    });
    return dt;
 }

Ответ 3

Ошибка можно устранить, изменив это:

dogTable = CreateDataTable(Dog);

:

dogTable = CreateDataTable(typeof(Dog));

Но есть некоторые предостережения с тем, что вы пытаетесь сделать. Во-первых, DataTable не может хранить сложные типы, поэтому, если Dog имеет экземпляр Cat на нем, вы не сможете добавить это как столбец. Это зависит от вас, что вы хотите сделать в этом случае, но помните об этом.

Во-вторых, я бы рекомендовал, чтобы единственный раз, когда вы используете DataTable, вы создаете код, который ничего не знает о потребляемых им данных. Для этого существуют допустимые варианты использования (например, пользовательский инструмент интеллектуального анализа данных). Если у вас уже есть данные в экземпляре Dog, просто используйте его.

Еще один маленький лакомый кусочек:

DataTable dogTable = new DataTable();
dogTable = CreateDataTable(Dog);

можно свести к следующему:

DataTable dogTable = CreateDataTable(Dog);

Ответ 4

Вот немного модифицированный код, который фиксировал часовой пояс для полей даты:

    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++)
            {
                if (props[i].PropertyType == typeof(DateTime))
                {
                    DateTime currDT = (DateTime)props[i].GetValue(item);
                    values[i] = currDT.ToUniversalTime();
                }
                else
                {
                    values[i] = props[i].GetValue(item);
                }
            }
            table.Rows.Add(values);
        }
        return table;
    }

Ответ 5

Используя ответ, предоставленный @neoistheone, я изменил следующие разделы. Сейчас работает отлично.

DataTable dogTable = new DataTable();
        dogTable = CreateDataTable(typeof(Dog));

        dogTable.Rows.Add(Killer.Breed, Killer.Name,Killer.legs,Killer.tail);

        foreach (DataRow row in dogTable.Rows)
        {
            Console.WriteLine(row.Field<string>("Name") + " " + row.Field<string>("Breed"));
            Console.ReadLine();
        }

Ответ 6

Здесь версия VB.Net, которая создает таблицу данных из общего списка, передается функции как объект. Существует также вспомогательная функция (ObjectToDataTable), которая создает таблицу данных из объекта.

Импорт System.Reflection

   Public Shared Function ListToDataTable(ByVal _List As Object) As DataTable

    Dim dt As New DataTable

    If _List.Count = 0 Then
        MsgBox("The list cannot be empty. This is a requirement of the ListToDataTable function.")
        Return dt
    End If

    Dim obj As Object = _List(0)
    dt = ObjectToDataTable(obj)
    Dim dr As DataRow = dt.NewRow

    For Each obj In _List

        dr = dt.NewRow

        For Each p as PropertyInfo In obj.GetType.GetProperties

            dr.Item(p.Name) = p.GetValue(obj, p.GetIndexParameters)

        Next

        dt.Rows.Add(dr)

    Next

    Return dt

End Function

Public Shared Function ObjectToDataTable(ByVal o As Object) As DataTable

    Dim dt As New DataTable
    Dim properties As List(Of PropertyInfo) = o.GetType.GetProperties.ToList()

    For Each prop As PropertyInfo In properties

        dt.Columns.Add(prop.Name, prop.PropertyType)

    Next

    dt.TableName = o.GetType.Name

    Return dt

End Function