Click here to Skip to main content
15,888,521 members
Articles / Database Development
Tip/Trick

C# Convert DataTable to List of Objects Dynamically

Rate me:
Please Sign up or sign in to vote.
4.76/5 (11 votes)
6 Dec 2014GPL32 min read 158.3K   3.9K   10   21
This article describes how to convert any Data Table to List of Objects at runtime using Reflection

Introduction

This tip describes how to convert any DataTable to List of Objects at runtime using Reflection.

Using the Code

I was refactoring a project that I did before and I noticed the need to convert the DataTables to their correspondent classes dynamically instead of repeating the whole code for every single DataTable, so I wrote and extension for DataTable and I used .NET reflection in order to be able to do it dynamically.

The idea is pretty simple.

  • Get the columns names and types for DataTable
  • Get the class attribute names and types
  • Write converts function for DataTable Data Types to your properties Data Types

Fill the object with the related field in the DataRow based on the field name, but to be able to do it smoothly, you need to have the DataTable column names match the class properties names and that’s about it.

C#
public static class Extensions
{
    /// <summary>
    /// Converts datatable to list<T> dynamically
    /// </summary>
    /// <typeparam name="T">Class name</typeparam>
    /// <param name="dataTable">data table to convert</param>
    /// <returns>List<T></returns>
    public static List<T> ToList<T>(this DataTable dataTable) where T : new()
    {
        var dataList = new List<T>();

        //Define what attributes to be read from the class
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

        //Read Attribute Names and Types
        var objFieldNames = typeof(T).GetProperties(flags).Cast<PropertyInfo>().
            Select(item => new 
            { 
                Name = item.Name, 
                Type = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType 
            }).ToList();

        //Read Datatable column names and types
        var dtlFieldNames = dataTable.Columns.Cast<DataColumn>().
            Select(item => new { 
                Name = item.ColumnName, 
                Type=item.DataType 
            }).ToList();

        foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
        {
            var classObj = new T();
           
            foreach (var dtField in dtlFieldNames)
            {
                PropertyInfo propertyInfos = classObj.GetType().GetProperty(dtField.Name);

                var field = objFieldNames.Find(x => x.Name == dtField.Name);

                if (field != null)
                {

                    if (propertyInfos.PropertyType == typeof(DateTime))
                    {
                        propertyInfos.SetValue
                        (classObj, convertToDateTime(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(int))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToInt(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(long))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToLong(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(decimal))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToDecimal(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(String))
                    {
                        if (dataRow[dtField.Name].GetType() == typeof(DateTime))
                        {
                            propertyInfos.SetValue
                            (classObj, ConvertToDateString(dataRow[dtField.Name]), null);
                        }
                        else
                        {
                            propertyInfos.SetValue
                            (classObj, ConvertToString(dataRow[dtField.Name]), null);
                        }
                    }
                }                
            }
            dataList.Add(classObj);
        }
        return dataList;
    }

    private static string ConvertToDateString(object date) 
    {
        if (date == null)
            return string.Empty;
       
        return SpecialDateTime.ConvertDate(Convert.ToDateTime(date));
    }

    private static string ConvertToString(object value)
    {
        return Convert.ToString(HelperFunctions.ReturnEmptyIfNull(value));
    }

    private static int ConvertToInt(object value) 
    {
        return Convert.ToInt32(HelperFunctions.ReturnZeroIfNull(value));
    }

    private static long ConvertToLong(object value)
    {
        return Convert.ToInt64(HelperFunctions.ReturnZeroIfNull(value));
    }

    private static decimal ConvertToDecimal(object value)
    {
        return Convert.ToDecimal(HelperFunctions.ReturnZeroIfNull(value));
    }

    private static DateTime convertToDateTime(object date)
    {
        return Convert.ToDateTime(HelperFunctions.ReturnDateTimeMinIfNull(date));
    }
}

Finally, you call it like this:

C#
List<MyClass> list =  dt.ToList<MyClass>

Why Do You Need Such a Scenario

Will it be an arguable thing. Reflection comes at a cost of performance because of all those steps to be taken to identify object Class methods and properties, and execute them at run time, but it will come in handy when you want to abstract a method to accept Type and you don’t have many types, or you have minimal data to set or get per Type, not to mention that you need to do this for every time that the method was called, some say why not cache it since it is a costly operation as somebody commented, well this is also debatable how important is the data and what is the performance that you will get for such method in case all your data have a small footprint but a lot. Anyway, there are a lot of factors that should be taken into consideration when you come to a cross road and ask yourself if you need to cache objects? But this is beyond the scope of this tip.

What I’m trying to convey in this tip is how to use reflection to generalize the conversion from DataTable to a List of Objects and that’s about it. You can do the same thing in different ways but it all goes down on the same factors Readability, Performance, Scalability, and as a personal preference I always choose Readability, Scalability, and flexibility over performance if the later was negligible or find some moderate solution for the problem if performance was pretty poor.

History

  • Version 1.0 - > 2014-12-06

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Team Leader CCC
Greece Greece
Nothing Much i love reading and developing new things and thats about it

Comments and Discussions

 
QuestionAwesome Pin
Member 1454224526-Jul-19 2:14
Member 1454224526-Jul-19 2:14 
PraiseThanks Pin
Danial Pato1-Jun-19 6:18
Danial Pato1-Jun-19 6:18 
QuestionWhat is SpecialDateTime? Pin
nbdxkfq11-Dec-15 23:43
nbdxkfq11-Dec-15 23:43 
AnswerRe: What is SpecialDateTime? Pin
sasavranic4-Jun-16 9:48
sasavranic4-Jun-16 9:48 
It's a typo....

It have to be like this:
C#
return HelperFunctions.ConvertDate....

GeneralRe: What is SpecialDateTime? Pin
saddam abu ghaida6-Jun-16 0:58
professionalsaddam abu ghaida6-Jun-16 0:58 
QuestionCA1002: Do not expose generic lists Pin
Luciano.Paes11-Feb-15 4:05
Luciano.Paes11-Feb-15 4:05 
QuestionExcellent Work but !!!!! Pin
MSamir7210-Dec-14 2:51
MSamir7210-Dec-14 2:51 
AnswerRe: Excellent Work but !!!!! Pin
saddam abu ghaida10-Dec-14 10:08
professionalsaddam abu ghaida10-Dec-14 10:08 
QuestionDoesnt work for null values Pin
guidingstructures9-Dec-14 11:40
guidingstructures9-Dec-14 11:40 
GeneralRe: Doesnt work for null values Pin
PIEBALDconsult9-Dec-14 13:19
mvePIEBALDconsult9-Dec-14 13:19 
QuestionNo Source code? Pin
DumpsterJuice8-Dec-14 7:53
DumpsterJuice8-Dec-14 7:53 
AnswerRe: No Source code? Pin
saddam abu ghaida8-Dec-14 20:56
professionalsaddam abu ghaida8-Dec-14 20:56 
GeneralRe: No Source code? Pin
Member 1144573427-Apr-15 10:20
Member 1144573427-Apr-15 10:20 
GeneralRe: No Source code? Pin
SgtWingHead13-Jul-15 0:40
SgtWingHead13-Jul-15 0:40 
GeneralRe: No Source code? Pin
saddam abu ghaida16-Jul-15 1:05
professionalsaddam abu ghaida16-Jul-15 1:05 
QuestionAutoMapper Pin
Hybertz7-Dec-14 0:08
Hybertz7-Dec-14 0:08 
AnswerRe: AutoMapper Pin
saddam abu ghaida7-Dec-14 1:09
professionalsaddam abu ghaida7-Dec-14 1:09 
GeneralRe: AutoMapper Pin
Jörgen Andersson7-Dec-14 8:53
professionalJörgen Andersson7-Dec-14 8:53 
GeneralThoughts Pin
PIEBALDconsult6-Dec-14 12:01
mvePIEBALDconsult6-Dec-14 12:01 
GeneralRe: Thoughts Pin
saddam abu ghaida6-Dec-14 14:19
professionalsaddam abu ghaida6-Dec-14 14:19 
GeneralRe: Thoughts Pin
PIEBALDconsult6-Dec-14 18:47
mvePIEBALDconsult6-Dec-14 18:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.