一尘不染

将通用列表/可枚举转换为数据表?

c#

我有几种方法可以返回不同的通用列表。

.net中是否存在任何类静态方法或将任何列表转换为数据表的方法?我能想象的唯一一件事就是使用反射来做到这一点。

如果我有这个:

List<Whatever> whatever = new List<Whatever>();

(下面的代码当然行不通,但是我希望有以下可能性:

DataTable dt = (DataTable) whatever;

阅读 280

收藏
2020-05-19

共1个答案

一尘不染

这是使用NuGet的FastMember进行的 2013年不错的更新:

IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data)) {
    table.Load(reader);
}

这使用FastMember的元编程API以获得最佳性能。如果要将其限制为特定成员(或强制执行命令),则也可以这样做:

IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
    table.Load(reader);
}

编辑的 Dis /声明者 FastMember是Marc Gravell的项目。它的黄金和全蝇!


是的,这与这个完全相反。反射就足够了-
或者如果您需要更快,则HyperDescriptor在2.0或Expression3.5中。实际上,HyperDescriptor应该绰绰有余。

例如:

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

现在只需一行,您就可以使它比反射快很多倍(通过启用HyperDescriptorobject-
type T)。


编辑再绩效查询;这是带有结果的测试台:

Vanilla 27179
Hyper   6997

我怀疑瓶颈已经从成员访问转变为DataTable绩效…我怀疑您会在此方面做很多改进…

码:

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        
    }
}
2020-05-19