汎用リスト/列挙型を DataTable に変換しますか? 質問する

汎用リスト/列挙型を DataTable に変換しますか? 質問する

異なる汎用リストを返すメソッドがいくつかあります。

.net には、リストをデータテーブルに変換するためのクラス静的メソッドなどはありますか? 私が想像できるのは、これを行うにはリフレクションを使用することだけです。

私がこれを持っている場合:

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

(次のコードはもちろん動作しませんが、次の可能性を実現したいと考えています。

DataTable dt = (DataTable) whatever;

ベストアンサー1

2013年の素晴らしいアップデートはこちらファストメンバー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 のプロジェクトです。金と完全なハエです!


はい、これはほぼ正反対ですこれ1つ; 反射で十分です - または、もっと早く必要な場合は、HyperDescriptor2.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;        
}

たった1行で、リフレクションよりも何倍も速く実行できます(HyperDescriptorオブジェクト タイプの場合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        
    }
}

おすすめ記事