c# - 将通用 List/Ienumerable 转换为 DataTable?

标签 c# list generics datatable

我几乎没有返回不同通用列表的方法。

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

如果我有这个:

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

(下一个代码当然不起作用,但我希望有可能:

DataTable dt = (DataTable) whatever;

最佳答案

这是一个不错的 2013 年更新,使用 FastMember来自 NuGet:

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

编辑的反对/声明:FastMember 是 Marc Gravell 的一个项目。这是金色的,满满的苍蝇!


是的,这与 this 几乎完全相反一;反射就足够了——或者如果你需要更快,HyperDescriptor在 2.0 中,或者在 3.5 中可能是 Expression。实际上,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;        
}

现在只需一行,您就可以比反射快很多倍(通过为对象类型 T 启用 HyperDescriptor)。


编辑重新性能查询;这是一个带有结果的测试装置:

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

关于c# - 将通用 List/Ienumerable 转换为 DataTable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/564366/

相关文章:

java - 你如何比较java中相同泛型类型的两个值?

java - Moshi 无法使用泛型为类创建转换器

c# - 如何更改 WPF 中不确定进度条动画的速度和宽度?

python - 如何确保字符串的格式正确

java - 如何遍历Hashmap中的对象

python - 如何通过从用户输入中删除哪个值来从列表(整数和字符串)中删除整数?

generics - 为什么在使用 sort_by_key 对向量进行排序时不能使用返回引用的键函数?

c# - 从字符串向 'RichTextBox' 插入新行?

c# - 如何在程序之前运行测试?

c# - 将月差添加到新日期