J'ai une liste générique d'objets. Chaque objet a 9 propriétés de chaîne. Je veux transformer cette liste en un ensemble de données que je peux transmettre à un datagridview ...... Quel est le meilleur moyen de s'y prendre?
Avez-vous essayé de lier directement la liste à la datagridview? Sinon, essayez-le d'abord car cela vous évitera beaucoup de douleur. Si vous avez déjà essayé, dites-nous ce qui ne va pas pour que nous puissions mieux vous conseiller. La liaison de données vous donne un comportement différent en fonction des interfaces implémentées par votre objet de données. Par exemple, si votre objet de données implémente uniquement IEnumerable
(par exemple List
), vous obtiendrez une liaison unidirectionnelle très basique, mais s'il implémente également IBindingList
(par exemple BindingList
, DataView
), vous obtiendrez une liaison bidirectionnelle.
Je m'excuse d'avoir fourni une réponse à cette question, mais je me suis dit que ce serait le moyen le plus simple de visualiser mon code final. Il inclut des correctifs pour les types Nullable et les valeurs NULL :-)
public static DataSet ToDataSet<T>(this IList<T> list)
{
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
//go through each property on T and add each value to the table
foreach (T item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
return ds;
}
Il y a un bogue avec le code d'extension de Lee ci-dessus, vous devez ajouter la ligne nouvellement remplie au tableau t lors de l'itération des éléments de la liste.
public static DataSet ToDataSet<T>(this IList<T> list) {
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach(var propInfo in elementType.GetProperties())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//go through each property on T and add each value to the table
foreach(T item in list)
{
DataRow row = t.NewRow();
foreach(var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null);
}
//This line was missing:
t.Rows.Add(row);
}
return ds;
}
Vous pouvez créer une méthode d'extension pour ajouter toutes les valeurs de propriété par réflexion:
public static DataSet ToDataSet<T>(this IList<T> list)
{
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach(var propInfo in elementType.GetProperties())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//go through each property on T and add each value to the table
foreach(T item in list)
{
DataRow row = t.NewRow();
foreach(var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null);
}
}
return ds;
}
Vous voudrez peut-être vérifier
http://www.codeproject.com/KB/vb/List2DataSet.aspx
Donne quelques approches différentes.
Code de force brute pour répondre à votre question:
DataTable dt = new DataTable();
//for each of your properties
dt.Columns.Add("PropertyOne", typeof(string));
foreach(Entity entity in entities)
{
DataRow row = dt.NewRow();
//foreach of your properties
row["PropertyOne"] = entity.PropertyOne;
dt.Rows.Add(row);
}
DataSet ds = new DataSet();
ds.Tables.Add(dt);
return ds;
Maintenant pour la question réelle. Pourquoi voudriez-vous faire cela? Comme mentionné précédemment, vous pouvez vous lier directement à une liste d'objets. Peut-être un outil de reporting qui ne prend que des jeux de données?
J'ai moi-même écrit une petite bibliothèque pour accomplir cette tâche. Il utilise la réflexion uniquement pour la première fois qu'un type d'objet doit être traduit en un datatable. Il émet une méthode qui fera tout le travail en traduisant un type d'objet.
C'est la solution la plus rapide que je connaisse (c'est pourquoi je l'ai développée :-)). Vous pouvez le trouver ici: ModelShredder sur GoogleCode
Actuellement, il ne prend en charge que la traduction vers un DataTable. Lorsque vous avez formulé votre question, cela devrait suffire. Le support des DataSets (pensez à un simple ORM inversé) est déjà développé, il sera publié en deux points faibles à mon retour de vacances :-)
J'ai légèrement modifié la réponse acceptée en traitant les types de valeur. Je suis tombé sur cette erreur en essayant de faire ce qui suit et parce que GetProperties () est zéro longueur pour les types valeur, je recevais un ensemble de données vide. Je sais que ce n'est pas le cas d'utilisation du PO, mais je pensais publier ce changement au cas où quelqu'un d'autre rencontrerait la même chose.
Enumerable.Range(1, 10).ToList().ToDataSet();
public static DataSet ToDataSet<T>(this IList<T> list)
{
var elementType = typeof(T);
var ds = new DataSet();
var t = new DataTable();
ds.Tables.Add(t);
if (elementType.IsValueType)
{
var colType = Nullable.GetUnderlyingType(elementType) ?? elementType;
t.Columns.Add(elementType.Name, colType);
} else
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
var colType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, colType);
}
}
//go through each property on T and add each value to the table
foreach (var item in list)
{
var row = t.NewRow();
if (elementType.IsValueType)
{
row[elementType.Name] = item;
}
else
{
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
}
t.Rows.Add(row);
}
return ds;
}
J'ai trouvé ce code sur le forum Microsoft. C’est à ce jour l’un des moyens les plus simples, faciles à comprendre et à utiliser. Cela m'a permis d'économiser des heures, je l'ai personnalisé comme méthode d'extension sans aucun changement de méthode. Ci-dessous le code. cela n'exige pas beaucoup d'explications.
Vous pouvez utiliser deux signatures de fonction avec la même implémentation
1) DataSet ToDataSetFromObject statique public (cet objet dsCollection)
2) public DataSet ToDataSetFromArrayOfObject (cet objet [] arrCollection). Je vais utiliser celui-ci par exemple.
// <summary>
// Serialize Object to XML and then read it into a DataSet:
// </summary>
// <param name="arrCollection">Array of object</param>
// <returns>dataset</returns>
public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection)
{
DataSet ds = new DataSet();
try {
XmlSerializer serializer = new XmlSerializer(arrCollection.GetType);
System.IO.StringWriter sw = new System.IO.StringWriter();
serializer.Serialize(sw, dsCollection);
System.IO.StringReader reader = new System.IO.StringReader(sw.ToString());
ds.ReadXml(reader);
} catch (Exception ex) {
throw (new Exception("Error While Converting Array of Object to Dataset."));
}
return ds;
}
Pour utiliser cette extension dans le code
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}
Une option serait d'utiliser un System.ComponenetModel.BindingList plutôt qu'une liste.
Cela vous permet de l'utiliser directement dans un DataGridView. Et contrairement à un System.Collections.Generic.List normal met à jour le DataGridView sur les modifications.