在 C# 中将通用列表转换为数据集 [关闭]

Posted

技术标签:

【中文标题】在 C# 中将通用列表转换为数据集 [关闭]【英文标题】:Convert generic list to dataset in C# [closed] 【发布时间】:2010-11-17 18:08:04 【问题描述】:

我有一个通用对象列表。每个对象有 9 个字符串属性。我想将该列表转换为可以传递给 datagridview 的数据集......这样做的最佳方法是什么?

【问题讨论】:

How do I transform a List<T> into a DataSet?的可能重复 【参考方案1】:

我在 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();

【讨论】:

【参考方案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;

【讨论】:

【参考方案3】:

对于为这个问题提供答案,我深表歉意,但我认为这将是查看最终代码的最简单方法。它包括可空类型和空值的修复:-)

    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;
    

【讨论】:

谢谢你,伟大的 sn-p :) 只有一个错误修复,我在 foreach 之前添加了 if (list.Count() != 0),因为如果你不想转换的列表是空的, 代码会抛出异常。 关于此 sn-p 的注意事项 - 您需要在 return ds; 之前添加 t.AcceptChanges(),否则,该表将被解释为包含您添加的所有行作为待定更改。这很少会导致任何问题,但它可以。 @AndrewGray 我猜这意味着这些行带有一个“脏”标志,因为它们被添加了?这可能是一种期望的行为? 可以,但并非总是如此。大多数时候 - 我会说 > 90% - 它是无害的。【参考方案4】:

上面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;

【讨论】:

【参考方案5】:

您可以创建一个扩展方法来通过反射添加所有属性值:

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;

【讨论】:

感谢代码,不过有一个小问题,可空类型正在轰炸...我将尝试修改它以适应它们,但我不是反射专家。如果我解决了问题,我会发布更新:-) 好的,我必须进行两项更改,一项用于 Nullable 类型,另一项用于空值... t.Columns.Add(propInfo.Name, propInfo.PropertyType);变为 Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; t.Columns.Add(propInfo.Name, ColType);和 row[propInfo.Name] = propInfo.GetValue(item, null);变成 row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.值;感谢您的代码:-)【参考方案6】:

您是否尝试过将列表直接绑定到 datagridview?如果没有,请先尝试,因为它会为您节省很多痛苦。如果您已经尝试过,请告诉我们出了什么问题,以便我们更好地为您提供建议。数据绑定根据数据对象实现的接口为您提供不同的行为。例如,如果您的数据对象只实现了IEnumerable(例如List),您将获得非常基本的单向绑定,但如果它也实现了IBindingList(例如BindingListDataView),那么你得到双向绑定。

【讨论】:

直接绑定通常不会成功:它很慢,而且排序很痛苦。如果它只有 1000 行就可以了,对于其他一切我推荐一个快速的数据表翻译器,比如我的 ModelShredder(见下文) 排序很痛苦。过滤也是如此。编辑也是如此。可以构建一个支持 DataTable 所做的所有用例的对象,但这并不是一项微不足道的工作 - 尤其是与仅将数据复制到 DataTable 相比。 是的,这就是我写模型粉碎机的原因。恐怕编辑当然不支持,但我不认为这是一个问题,因为我认为出于上述原因应该避免编辑表格中的数据。总是有 excel :-) 这取决于您的用例。如果您正在编写一个 2 层应用程序,那么排序、过滤、分页等最容易在 DataSet/Table/View 中完成。但是,如果您正在编写一个 3 层应用程序,那么所有这些事情都已经在业务层上完成了,而您在表示层上所要做的就是一个非常愚蠢的单向绑定到一个通用列表。跨度> 【参考方案7】:

蛮力代码回答你的问题:

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;

现在是实际问题。你为什么想做这个?如前所述,您可以直接绑定到对象列表。也许是一个只需要数据集的报告工具?

【讨论】:

无论如何,我为什么要这样做的答案是 WCF。服务真的不喜欢把泛型放在网上。我正在编写一些代码来从存储库返回分页和排序的结果,我现在正在处理一个数据集......一个原因是返回的字段并不总是相同的......我不是确定这是否可行,它可能需要 DTO,这意味着我还有其他问题,但我离题了 :-)【参考方案8】:

一种选择是使用 System.ComponenetModel.BindingList 而不是列表。

这允许您直接在 DataGridView 中使用它。并且与普通的 System.Collections.Generic.List 不同,它会根据更改更新 DataGridView。

【讨论】:

以上是关于在 C# 中将通用列表转换为数据集 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将 DataTable 转换为通用列表

将数据集转换为列表

如何在 Scala 中将数据帧转换为 Apache Spark 中的数据集?

如何在 VB.NET 中将 '<unnamed portal 1>' 转换为 plpgsql 函数的数据集

如何在Apache Spark Java中将数组类型的数据集转换为字符串类型

如何在 C# 中将数据集加载到 libsvm 中