使用Reflection从类创建DataTable?

我刚刚学习了generics,我想知道我是否可以用它来动态地从我的类中构建数据表。

或者我可能在这里忽略了这一点。 这是我的代码,我要做的是从我现有的类创建一个数据表并填充它。 但是我陷入了思考过程中。

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类实际填充数据?

在所有以前的答案的基础上,这是一个从任何集合创建DataTable的版本:

 public static DataTable CreateDataTable(IEnumerable 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; } 

我最喜欢的自制function。 它可以同时创建和填充所有内容。 抛出任何物体。

  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; } 

可以通过更改此错误来解决此错误:

 dogTable = CreateDataTable(Dog); 

对此:

 dogTable = CreateDataTable(typeof(Dog)); 

但是你要做的事情有一些警告。 首先, DataTable无法存储复杂类型,因此如果DogCat实例,您将无法将其添加为列。 这取决于你在这种情况下你想做什么,但要记住它。

其次,我建议您使用DataTable的唯一时间是在构建对其消耗的数据一无所知的代码时。 有一些有效的用例(例如用户驱动的数据挖掘工具)。 如果您已经拥有Dog实例中的数据,请使用它。

另一个小小的问题,这个:

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

可以浓缩到这个:

 DataTable dogTable = CreateDataTable(Dog); 

这是David的答案的更紧凑版本,也是一个扩展function。 我已经在Github的C#项目中发布了代码。

 public static class Extensions { public static DataTable ToDataTable(this IEnumerable self) { var properties = typeof(T).GetProperties(); var dataTable = new DataTable(); foreach (var info in properties) dataTable.Columns.Add(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType); foreach (var entity in self) dataTable.Rows.Add(properties.Select(p => p.GetValue(entity)).ToArray()); return dataTable; } } 

我发现这与将DataTable写入CSV的代码结合使用效果非常好。

这是一个稍微修改过的代码,它修复了datatime字段的时区问题:

  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++) { 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; } 

使用@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("Name") + " " + row.Field("Breed")); Console.ReadLine(); } 

这是一个VB.Net版本,它从作为对象传递给函数的generics列表中创建数据表。 还有一个辅助函数(ObjectToDataTable),它从对象创建数据表。

Imports 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 

您可以将对象转换为xml,然后将xml文档加载到数据集,然后从数据集中提取第一个表。 但是,我不知道这是如何实用的,因为它推断创建流,数据集和数据表,并使用转换来创建xml文档。

我想为了概念certificate我能理解为什么。 这是一个例子,但有点犹豫使用它。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Data; using System.Xml.Serialization; 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(Object[] arr) { XmlSerializer serializer = new XmlSerializer(arr.GetType()); System.IO.StringWriter sw = new System.IO.StringWriter(); serializer.Serialize(sw, arr); System.Data.DataSet ds = new System.Data.DataSet(); System.Data.DataTable dt = new System.Data.DataTable(); System.IO.StringReader reader = new System.IO.StringReader(sw.ToString()); ds.ReadXml(reader); return ds.Tables[0]; } static void Main(string[] args) { Dog Killer = new Dog(); Killer.Breed = "Maltese Poodle"; Killer.legs = 3; Killer.tail = false; Killer.Name = "Killer"; Dog [] array_dog = new Dog[5]; Dog [0] = killer; Dog [1] = killer; Dog [2] = killer; Dog [3] = killer; Dog [4] = killer; DataTable dogTable = new DataTable(); dogTable = CreateDataTable(array_dog); // continue here } } } 

在这里看下面的例子