C# 使用反射从类创建数据表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18746064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Reflection to create a DataTable from a Class?
提问by vwdewaal
I've just learned about Generics and I'm wondering whether I can use it to dynamically build datatables from my classes.
我刚刚了解了泛型,我想知道是否可以使用它从我的类中动态构建数据表。
Or I might be missing the point here. Here is my code, what I'm trying to do is create a datatable from my existing class and populate it. However I'm getting stuck in my thought process.
或者我可能在这里错过了重点。这是我的代码,我想要做的是从我现有的类创建一个数据表并填充它。然而,我陷入了我的思考过程。
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?
}
}
}
Now At the DataTable
point it errors.
Also, being new to reflection and Generics, how will I actually populate the data with the Killer class?
现在DataTable
它出错了。另外,作为反射和泛型的新手,我将如何使用 Killer 类实际填充数据?
采纳答案by David Airapetyan
Building up on all the previous answers, here is a version that creates a DataTable from any collection:
建立在所有以前的答案的基础上,这是一个从任何集合创建 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;
}
回答by Mike Perrenoud
The error can be resolved by changing this:
可以通过更改以下内容来解决错误:
dogTable = CreateDataTable(Dog);
to this:
对此:
dogTable = CreateDataTable(typeof(Dog));
But there are some caveats with what you're trying to do. First, a DataTable
can't store complex types, so if Dog
has an instance of Cat
on it, you won't be able to add that as a column. It's up to you what you want to do in that case, but keep it in mind.
但是,您要尝试执行的操作有一些注意事项。首先, aDataTable
不能存储复杂类型,因此如果上面Dog
有一个实例Cat
,您将无法将其添加为列。在这种情况下,您想做什么取决于您,但请记住这一点。
Second, I would recommend that the only time you use a DataTable
is when you're building code that knows nothingabout the data its consuming. There are valid use cases for this (e.g. a user-driven data mining tool). If you already have the data in the Dog
instance, just use it.
其次,我建议您使用 a 的唯一时间DataTable
是在构建对其消耗的数据一无所知的代码时。这有一些有效的用例(例如用户驱动的数据挖掘工具)。如果您已经在Dog
实例中拥有数据,只需使用它。
Another little tidbit, this:
另一个小花絮,这个:
DataTable dogTable = new DataTable();
dogTable = CreateDataTable(Dog);
can be condensed to this:
可以浓缩为:
DataTable dogTable = CreateDataTable(Dog);
回答by vwdewaal
Using the answer provided by @neoistheone I've changed the following sections. Works fine now.
使用@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();
}
回答by Franck
my favorite homemade function. it create and populate all at same time. throw any object.
我最喜欢的自制功能。它同时创建和填充。扔任何物体。
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;
}
回答by Michael Bross
Here's a VB.Net version that creates a data table from a generic list passed to the function as an object. There is also a helper function (ObjectToDataTable) that creates a data table from an object.
这是一个 VB.Net 版本,它从作为对象传递给函数的通用列表创建数据表。还有一个辅助函数 (ObjectToDataTable) 可以从对象创建数据表。
Imports System.Reflection
导入 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
回答by Krasimir Slaveykov
Here is a little bit modified code, which fixed time zone issue for datatime fields:
这是一些修改后的代码,它修复了数据时间字段的时区问题:
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;
}
回答by CESAR NICOLINI RIVERO
you can convert the object to xml then load the xml document to a dataset, then extract the first table out of the data set. However i dont see how this be practical as it infers creating streams, datasets & datatables and using converstions to create the xml document.
您可以将对象转换为 xml,然后将 xml 文档加载到数据集,然后从数据集中提取第一个表。但是我不明白这如何实用,因为它推断创建流、数据集和数据表并使用转换来创建 xml 文档。
I guess for proof of concept i can understand why. Here is an example, but somewhat hesitant to use it.
我想对于概念证明,我可以理解为什么。这是一个例子,但对使用它有些犹豫。
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
}
}
}
look the following example here
在此处查看以下示例
回答by cdiggins
Here is a more compact version of David's answerthat is also an extension function. I've posted the code in a C# project on Github.
这是大卫答案的更紧凑版本,它也是一个扩展功能。我已经在 Github 上的C# 项目中发布了代码。
public static class Extensions
{
public static DataTable ToDataTable<T>(this IEnumerable<T> 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;
}
}
I have found that this works very well in conjunction with code to write a DataTable to CSV.