Đây là một bản cập nhật 2013 tuyệt vời sử dụng FastMember từ NuGet:
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data)) {
table.Load(reader);
}
Điều này sử dụng API lập trình meta của FastMember để có hiệu suất tối đa. Nếu bạn muốn hạn chế nó cho các thành viên cụ thể (hoặc thực thi lệnh), thì bạn cũng có thể làm điều đó:
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
table.Load(reader);
}
Dis / aimer của biên tập viên : FastMember là một dự án của Marc Gravell. Vàng và bay đầy đủ của nó!
Vâng, điều này hoàn toàn trái ngược với điều này ; sự phản chiếu sẽ đủ - hoặc nếu bạn cần nhanh hơn, HyperDescriptor
trong 2.0 hoặc có thể Expression
trong 3.5. Trên thực tế, HyperDescriptor
nên được nhiều hơn đầy đủ.
Ví dụ:
// remove "this" if not on C# 3.0 / .NET 3.5
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++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Bây giờ với một dòng, bạn có thể thực hiện việc này nhanh hơn nhiều lần so với phản chiếu (bằng cách bật HyperDescriptor
loại đối tượng T
).
chỉnh sửa lại truy vấn hiệu suất; đây là một thử nghiệm với kết quả:
Vanilla 27179
Hyper 6997
Tôi nghi ngờ rằng nút cổ chai đã chuyển từ quyền truy cập của thành viên sang DataTable
hiệu suất ... Tôi nghi ngờ bạn sẽ cải thiện nhiều về điều đó ...
mã:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
public class MyData
{
public int A { get; set; }
public string B { get; set; }
public DateTime C { get; set; }
public decimal D { get; set; }
public string E { get; set; }
public int F { get; set; }
}
static class Program
{
static void RunTest(List<MyData> data, string caption)
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < 500; i++)
{
data.ToDataTable();
}
watch.Stop();
Console.WriteLine(caption + "\t" + watch.ElapsedMilliseconds);
}
static void Main()
{
List<MyData> foos = new List<MyData>();
for (int i = 0 ; i < 5000 ; i++ ){
foos.Add(new MyData
{ // just gibberish...
A = i,
B = i.ToString(),
C = DateTime.Now.AddSeconds(i),
D = i,
E = "hello",
F = i * 2
});
}
RunTest(foos, "Vanilla");
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(
typeof(MyData));
RunTest(foos, "Hyper");
Console.ReadLine(); // return to exit
}
}