Voici une belle mise à jour de 2013 utilisant FastMember de NuGet :
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data)) {
table.Load(reader);
}
Ceci utilise l'API de métaprogrammation de FastMember pour une performance maximale. Si vous voulez le restreindre à des membres particuliers (ou faire respecter l'ordre), vous pouvez également le faire :
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
table.Load(reader);
}
L'éditeur Dis / revendicateur : FastMember est un projet de Marc Gravell. C'est de l'or et des mouches pleines !
Oui, c'est à peu près l'exact opposé de ce un ; la réflexion suffirait - ou si vous avez besoin de plus rapide, HyperDescriptor
dans la version 2.0, ou peut-être Expression
en 3.5. En fait, HyperDescriptor
devrait être plus que suffisant.
Par exemple :
// 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;
}
Maintenant, avec une seule ligne, vous pouvez rendre ce processus beaucoup plus rapide que la réflexion (en activant l'option HyperDescriptor
pour le type d'objet T
).
Modification de la requête de performance ; voici un banc d'essai avec les résultats :
Vanilla 27179
Hyper 6997
Je soupçonne que le goulot d'étranglement s'est déplacé de l'accès aux membres vers DataTable
performance... Je doute que vous puissiez améliorer beaucoup cela...
Code :
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
}
}
2 votes
Bien sûr, une bonne question serait "pourquoi ?" - alors que List<T> est dans de nombreux cas un meilleur outil que DataTable ;-p Chacun son truc, je suppose...
1 votes
Je pense que celle-ci est peut-être un double de cette question : stackoverflow.com/questions/523153/ Il a même une réponse presque identique :-)
2 votes
@MarcGravell : Mon "pourquoi ?" est la manipulation de List<T> (Traverser les colonnes et les lignes). J'essaie de faire un pivot à partir d'une List<T> et accéder aux propriétés via la réflexion c'est une douleur. Est-ce que je m'y prends mal ?
1 votes
@Eduardo il y a un grand nombre d'outils pour supprimer la douleur de la réflexion - FastMember me vient à l'esprit. Il s'agit de pourrait Il se peut aussi qu'une DataTable soit utile à des scénarios spécifiques - tout dépend du contexte. Peut-être que le plus gros problème est que les gens utilisent DataTable pour tout stockage de données juste parce qu'il existe sans prendre le temps d'examiner les options et leur scénario.
0 votes
@EduardoMolteni si vous êtes intéressé, j'ai mis à jour FastMember pour avoir un support direct pour cela - voir la réponse mise à jour.
0 votes
Si vous voulez seulement pivoter, pourquoi ne pas utiliser la linqLib. linqlib.codeplex.com il implémente presque tout ce à quoi on peut penser pour IEnumerable.
0 votes
Poste croisé avec cette réponse qui m'a aidé. stackoverflow.com/questions/3839022/listt-to-dataview