オブジェクトの汎用リストがあります。各オブジェクトには9つの文字列プロパティがあります。そのリストをデータグリッドビューに渡すことができるデータセットに変換したい......これを行うための最善の方法は何ですか?
リストをdatagridviewに直接バインドしようとしましたか?そうでない場合は、最初に試してみてください。多くの痛みが軽減されるからです。既に試してみた場合は、何がおかしいのか教えてください。データバインディングは、データオブジェクトが実装するインターフェイスに応じて異なる動作を提供します。たとえば、データオブジェクトがIEnumerable
(たとえばList
)のみを実装する場合、非常に基本的な一方向バインディングを取得しますが、IBindingList
も実装する場合(たとえばBindingList
、DataView
)、双方向バインディングを取得します。
この質問に答えてくれたことをおaびしますが、最終的なコードを表示する最も簡単な方法だと思いました。 nullable型と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;
}
上記のLeeの拡張コードにはバグがあります。リスト内の項目を繰り返し処理する場合、新しく記入された行をテーブルtに追加する必要があります。
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;
}
リフレクションを介してすべてのプロパティ値を追加する拡張メソッドを作成できます。
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;
}
質問に答えるためのブルートフォースコード:
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;
さて、実際の質問です。なぜあなたはこれをしたいのですか?前述のように、オブジェクトリストに直接バインドできます。データセットのみを取得するレポートツールですか?
このタスクを達成するために、自分で小さなライブラリを作成しました。オブジェクト型がデータテーブルに変換されるのは初めての場合にのみリフレクションを使用します。オブジェクト型を変換するすべての作業を行うメソッドを発行します。
私が知っている最速のソリューションです(だからこそ開発しました:-))。ここで見つけることができます: ModelShredder on GoogleCode
現在、DataTableへの変換のみをサポートしています。質問を述べたように、これで十分でしょう。 DataSetのサポート(単純な逆ORMのようなもの)はすでに開発されており、休暇から戻ったときに2つの弱点でリリースされます:-)
値タイプを処理することにより、受け入れられた回答をわずかに変更しました。次のことをしようとしたときにこれに遭遇しました。GetProperties()は値型の長さがゼロであるため、空のデータセットを取得していました。私はこれがOPのユースケースではないことを知っていますが、他の誰かが同じことを見つけた場合に備えてこの変更を投稿すると思いました。
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;
}
Microsoftフォーラムでこのコードを見つけました。これはこれまでのところ、最も簡単な方法の1つであり、理解と使用が簡単です。これにより時間を節約でき、実際の方法を変更せずに拡張方法としてカスタマイズしました。以下はコードです。多くの説明は必要ありません。
同じ実装で2つの関数シグネチャを使用できます
1)public static DataSet ToDataSetFromObject(this object dsCollection)
2)public static DataSet ToDataSetFromArrayOfObject(this object [] arrCollection)。たとえば、これを使用します。
// <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;
}
この拡張機能をコードで使用するには
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}
1つのオプションは、リストではなくSystem.ComponenetModel.BindingListを使用することです。
これにより、DataGridView内で直接使用できます。また、通常のSystem.Collections.Generic.Listとは異なり、変更時にDataGridViewを更新します。