【发布时间】:2010-11-17 18:08:04
【问题描述】:
我有一个通用对象列表。每个对象有 9 个字符串属性。我想将该列表转换为可以传递给 datagridview 的数据集......这样做的最佳方法是什么?
【问题讨论】:
我有一个通用对象列表。每个对象有 9 个字符串属性。我想将该列表转换为可以传递给 datagridview 的数据集......这样做的最佳方法是什么?
【问题讨论】:
我在 Microsoft 论坛上找到了此代码。这是迄今为止最简单的方法之一,易于理解和使用。这节省了我几个小时,我将其定制为扩展方法,而对实际方法没有任何改变。下面是代码。它不需要太多解释。
您可以使用两个具有相同实现的函数签名
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();
}
【讨论】:
我通过处理值类型稍微修改了接受的答案。我在尝试执行以下操作时遇到了这个问题,因为 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;
}
【讨论】:
对于为这个问题提供答案,我深表歉意,但我认为这将是查看最终代码的最简单方法。它包括可空类型和空值的修复:-)
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;
}
【讨论】:
return ds; 之前添加 t.AcceptChanges(),否则,该表将被解释为包含您添加的所有行作为待定更改。这很少会导致任何问题,但它可以。
上面Lee的扩展代码有一个bug,需要在遍历list中的item时,将新填充的行添加到表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;
}
【讨论】:
您是否尝试过将列表直接绑定到 datagridview?如果没有,请先尝试,因为它会为您节省很多痛苦。如果您已经尝试过,请告诉我们出了什么问题,以便我们更好地为您提供建议。数据绑定根据数据对象实现的接口为您提供不同的行为。例如,如果您的数据对象只实现了IEnumerable(例如List),您将获得非常基本的单向绑定,但如果它也实现了IBindingList(例如BindingList、DataView),那么你得到双向绑定。
【讨论】:
蛮力代码回答你的问题:
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;
现在是实际问题。你为什么想做这个?如前所述,您可以直接绑定到对象列表。也许是一个只需要数据集的报告工具?
【讨论】:
一种选择是使用 System.ComponenetModel.BindingList 而不是列表。
这允许您直接在 DataGridView 中使用它。并且与普通的 System.Collections.Generic.List 不同,它会根据更改更新 DataGridView。
【讨论】: