6

This question concerns generics and types as well as datatables.

The following snippet is around the net here and there, and creates a datatable based on a generic type:

public static DataTable ListToDataTable<T>(List<T> list)
{
    DataTable dt = new DataTable();

    foreach (PropertyInfo info in typeof(T).GetProperties())
    {
        dt.Columns.Add(new DataColumn(info.Name, info.PropertyType));
    }
    foreach (T t in list)
    {
        DataRow row = dt.NewRow();
        foreach (PropertyInfo info in typeof(T).GetProperties())
        {
            row[info.Name] = info.GetValue(t, null);
        }
        dt.Rows.Add(row);
    }
    return dt;
}

I'm using the excellent FileHelpers library to import batches of records into SQL Server. To use SqlBulkCopy I need a datatable with columns from a given type. Filehelpers can read in a .cs file at runtime and create your type based on that. eg:

System.Type userType = null;
userType = ClassBuilder.ClassFromSourceFile("myclassfile.cs");

I'd like to change the method above so it just creates the columns for me when passed a type (eg 'userType'). ie the method signature would be something like:

public static DataTable TypeToDataTable<T>(<T> myType)

and would return an empty dataset with columns, ready to have rows of userType added to it.

I've tried various methods - any ideas?

madth3
  • 7,275
  • 12
  • 50
  • 74
Glinkot
  • 2,924
  • 10
  • 42
  • 67

2 Answers2

13

It's actually pretty simple, when you realize that you don't need to (or even can) use generics in this case:

public static DataTable CreateEmptyDataTable(Type myType)
{
    DataTable dt = new DataTable();

    foreach (PropertyInfo info in myType.GetProperties())
    {
        dt.Columns.Add(new DataColumn(info.Name, info.PropertyType));
    }

    return dt;
}

You would call it like this:

System.Type userType = null;
userType = ClassBuilder.ClassFromSourceFile("myclassfile.cs");
DataTable emptyDataTable = CreateEmptyDataTable(userType);
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Thanks, that's perfect! For some foolish reason I was trying to put a in the parameters and your method is exactly the remedy. – Glinkot Jun 09 '11 at 10:33
6

Recently I needed exactly this and found it here on SO. I combined the premise in the question with the answer and decided to share the code since both are incomplete:

private DataTable CreateDataTableFromObjects<T>(List<T> items, string name = null)
{
    var myType = typeof(T);
    if (name == null)
    {
        name = myType.Name;
    }
    DataTable dt = new DataTable(name);
    foreach (PropertyInfo info in myType.GetProperties())
    {
        dt.Columns.Add(new DataColumn(info.Name, info.PropertyType));
    }
    foreach (var item in items)
    {
        DataRow dr = dt.NewRow();
        foreach (PropertyInfo info in myType.GetProperties())
        {
            dr[info.Name] = info.GetValue(item);
        }
        dt.Rows.Add(dr);
    }
    return dt;
}
vladimir123
  • 484
  • 6
  • 12