5

I have a Generic list of a class that I automatically convert it to DataTable using Reflection and extension methods.Now I want to do it in reverse direction.I want to convert DataTable to List.Better to say I want help to write a method that expect a DataTable and a Type and automatically find property of that type(class) according to column name and assign value to object of that Type(class).like this psodu code:

private List<T> ConvertToList<T>(DataTable dt)
{
    List<string> AllColumns = // Get All Column Names of a DataTable
    for(int i=0;i<dt.Rows.Count;i++)
    {
        foreach(var item in AllColumns )
        {
             //Get Property According To **ITEM**
             //Get Data Of Rows[i][item] and assign it to T.property
        }
    }
}

How I can do this?


Edit 1)

I use answer of @Cuong Le like this:

var properties = typeof(CustomType).GetProperties().ToList();
List<CustomType> list = ConvertToList<CustomType>(dt, properties);

and :

private List<T> ConvertToList<T>(DataTable dt,List<PropertyInfo> fields) where T : class
{
    return dt.AsEnumerable().Select(Convert<T>(fields)).ToList();  <------
}

private T Convert<T>(DataRow row,List<PropertyInfo> fields) where T : class
{
    var properties = typeof(T).GetProperties().ToList();

    var objT = Activator.CreateInstance<T>();
    foreach (var pro in properties)
    {
        pro.SetValue(objT, row[pro.Name],null);
    }

    return objT;
} 

but in line I place an arrow in front of it I got this two errors:

No overload for method 'Convert' takes 1 arguments

and

The type arguments for method 'System.Data.EnumerableRowCollectionExtensions.Select(System.Data.EnumerableRowCollection, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

How I can solve this problem?

Arian
  • 12,793
  • 66
  • 176
  • 300

1 Answers1

9

Use AsEnumerable() method to support LINQ:

    private List<T> ConvertToList<T>(DataTable dt)
    {
        var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();

        var properties = typeof(T).GetProperties();

        return dt.AsEnumerable().Select(row =>
            {
                var objT = Activator.CreateInstance<T>();

                foreach (var pro in properties)
                {
                    if (columnNames.Contains(pro.Name))
                        pro.SetValue(objT, row[pro.Name]);
                }

                return objT;
            }).ToList();

    }

GetProperties searches for the properties of the current Type, using the specified binding constraints.

The link in here: http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx

cuongle
  • 74,024
  • 28
  • 151
  • 206
  • 1
    Put the caret on `GetProperties` and press F1 – Zdeslav Vojkovic Sep 30 '12 at 15:27
  • @Kerezo: take a look in here: http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx – cuongle Sep 30 '12 at 15:28
  • thanks dear @CuongLe.But this code works if DataTable has all Columns corresponding to T.Properties. How I can pass List of column names to `Convert` and set just properties that has column? – Arian Sep 30 '12 at 15:39
  • Similar one as a extension method: https://gist.github.com/gaui/a0a615029f1327296cf8 – Gaui Jul 12 '14 at 16:16
  • Only issue I see with this in 2023 is that if your data table was populated from a database and contains System.DBNull values, those won't convert to null, even if the object property is nullable. The solution is to change the pro.SetValue() line to: pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : row[pro.Name]); – kooch Feb 10 '23 at 22:00