ma.citi

A Coder's Blog

How to generate datatable from generic list (C#)

I wanted to add an extension method to a generic list to convert it into a datatable in order to be used as input param in a Stored Procedure

public static DataTable ConvertToDataTable<T>(this List<T> myList)
{
    DataTable dt = new DataTable();

    var allProperties = typeof(T).GetProperties().ToList();

    //add all the columns
    allProperties.ForEach(x => dt.Columns.Add(x.Name));

    myList.ForEach(x =>
    {
        var row = dt.NewRow();

        var type = x.GetType();

        allProperties.ForEach(y =>
        {
            var propValue = type.GetProperty(y.Name).GetValue(x, null);

            //example: if I want to convert a boolean into a BIT
            ConversionAttr conversionType = y.GetCustomAttributes(typeof(ConversionAttr), false).FirstOrDefault() as ConversionAttr;

            row[y.Name] = (propValue != null && conversionType != null) ? Convert.ChangeType(propValue, conversionType.ConversionType) : propValue;

        });

        dt.Rows.Add(row);
    });

     return dt;
}

You can use a custom attribute for conversion, let’s say that for example you want to convert a bool into an int

public class ConversionAttribute : Attribute
{
    public Type ConversionType { get; set; }

    public ConversionAttribute(Type type)
    {
        this.ConversionType = type;
    }

}

Test it..

List<Test> t = new List<Test> { new Test { IsValid = true, Description = "This is a test" } };

DataTable dt =  t.ConvertToDataTable<Test>();


//....

public class Test
{
    [ConversionAttr(ConversionType = typeof(int))]
    public bool IsValid { get; set; }

    public string Description { get; set; }

	//etc..
}
			

I also wrote this simple method that can be useful in case you want to convert a datarow (returned by a SP) into a specific object..

public static T ConvertToObject<T>(this DataRow dr)
{
    var instance = Activator.CreateInstance<T>();

    for (int i = 0; i < dr.Table.Columns.Count; i++)
    {
        var prop = instance.GetType().GetProperty(dr.Table.Columns[i].ColumnName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

        if (prop != null)
            prop.SetValue(instance, Convert.ChangeType(dr[i], prop.PropertyType));
    }

    return instance;

}

//...

//var test = dataRow.ConvertToObject<Test>();