Использование 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