收录日期:2020/06/02 02:49:06 时间:2009-08-07 16:22:33 标签:c#,list,dataset

I have a Generic list of Objects. Each object has 9 string properties. I want to turn that list into a dataset that i can pass to a datagridview......Whats the best way to go about doing this?

Have you tried binding the list to the datagridview directly? If not, try that first because it will save you lots of pain. If you have tried it already, please tell us what went wrong so we can better advise you. Data binding gives you different behaviour depending on what interfaces your data object implements. For example, if your data object only implements IEnumerable (e.g. List), you will get very basic one-way binding, but if it implements IBindingList as well (e.g. BindingList, DataView), then you get two-way binding.

I apologize for putting an answer up to this question, but I figured it would be the easiest way to view my final code. It includes fixes for nullable types and null values :-)

    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;
    }

There is a bug with Lee's extension code above, you need to add the newly filled row to the table t when iterating throught the items in the list.

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;

}

You could create an extension method to add all property values through reflection:

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;
}

You may want to check out

http://www.codeproject.com/KB/vb/List2DataSet.aspx

Gives a few different approaches.

Brute force code to answer your 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;

Now for the actual question. Why would you want to do this? As mentioned earlier, you can bind directly to an object list. Maybe a reporting tool that only takes datasets?

I've written a small library myself to accomplish this task. It uses reflection only for the first time an object type is to be translated to a datatable. It emits a method that will do all the work translating an object type.

Its the fastest solution i know (thats why i developed it :-) ). You can find it here: ModelShredder on GoogleCode

Currently it is only supporting translation to a DataTable. As you phrased your question, this should be sufficient. Support for DataSets (think of a simple reverse ORM) is already developed, it will be released in two weaks when i am back from vacation :-)

I have slightly modified the accepted answer by handling value types. I came across this when trying to do the following and because GetProperties() is zero length for value types I was getting an empty dataset. I know this is not the use case for the OP but thought I'd post this change in case anyone else came across the same thing.

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;
}

One option would be to use a System.ComponenetModel.BindingList rather than a list.

This allows you to use it directly within a DataGridView. And unlike a normal System.Collections.Generic.List updates the DataGridView on changes.

Convert generic list to dataset in C# .Net: Convert Generic List of Objects to DataSet Convert DataTable to generic List? Convert Generic List to bytes Linq to Sql convert to generic list in VB.NET convert .NET generic List to F# list List of Structs or Dataset in C#? Convert generic List/Enumerable to DataTable? C# Convert Byte Array to Generic List Convert linq model to generic list How do you convert a DataSet/DataTable into a generic list of certain type? How to return a generic list collection in C#? How to compare custom generic List<> in C#? C#: convert generic pointer to array Generic list manipulation function in C? How can I convert List to Hashtable in C#? Fastest way to convert datatable to generic list Linq to object: ToList can not convert to generic list