Populating a Generic Data List with Generic method

This approach helps us not to customize our Data Access Layer for different type of data classes. Consider we have some "Data class" in our application and we want the data class to act as a collection, Generally what  we do is declare a "Generic List" (New feature in 2.0) of that data class type and populate our data list from the database.

For populating the list, we loop through the data class with customized code and add the class to our list collection. This will be tedious and time consuming if we have hundreds of classes where we need to rewrite the same code again and again.

To avoid that I have conceived a new approach where we can pass the object of the class as a parameter and as a output we get a Generic Data List. Then we can typecast the Generic list back to our custom List collection.This is accomplished using reflection.

In the below example I will explain how to do it, consider we have a data class called Person.

Data Class Person Data Object

public class Person
{
   // Required to create multiple instance through reflection
    public object Clone()

    {
        Person person = new Person();
       
return (object)person;
    }

     private string _Name;
     public string Name

     {
      set{_Name=value;}
      get { return _Name; } 
     }

    private string _Address;
    public string Address
    {
        set { _Address = value; }
        get { return _Address; }
    }

    private string _City;
    public string City
    {
        set { _City = value; }
        get { return _City; }
    }

    private string _State;
    public string State
    {
        set { _State = value; }
        get { return _State; }
    }

    private string _Country;
    public string Country
    {
        set { _Country = value; }
        get { return _State; }
    }

In UI create the instance of the Data object and pass it to the method "ExecuteGenericList". ExecuteGenericList method process the passed object and creates a collection of the object depending upon number of rows we get from our select query. Little bit of type casting has to be done to the returned Generic List to convert it to our typed data list Person.

UI Page Load
 
//Create instance of data object
        Person person = new Person();
        DAL dal = new DAL();

       // dal.ExecuteGenericList(person) returns a Generic data list of the type  person

      // ConvertAll<Person>(new Converter<object, Person>(delegate(object o) { return (Person)o; })); typecasts the generic list to the type   List<Person> 
      
        List<Person> lstPerson = dal.ExecuteGenericList(person).ConvertAll<Person>(new Converter<object, Person>(delegate(object o) { return (Person)o; }));

        // Can be assigned to a DataSource
        GridView1.DataSource = lstPerson;
        GridView1.DataBind();

Our DAL class "ExecuteGenericList" uses reflection to iterate through all the properties of the class and creates a generic list collection for each and every row

DAL  Where our object is read and returned as List

    /// <summary>
    /// ExecuteGenericList is used to fill all properties any passed  data object
    /// Author :Sridhar Subramanian
    /// </summary>
    /// <param name="objectClass">Object which type has to be filled and returned as Generic List</param>
    /// <param name="parameter1">SQL query parameter,you can use SP </param>
    /// <returns>Generic List of the passed type </returns>
    public List<Object> ExecuteGenericList(object objectClass)
    {
        List<Object> lstGenric = null;
        try
        {
            sqlConnection = new SqlConnection(@"Server=SridharDev;Database=EntLibTest;Uid=Test;Pwd=Test;");
            sqlConnection.Open();
            sqlCommand = new SqlCommand("SELECT * FROM PERSON", sqlConnection);
            sqlDataReader = sqlCommand.ExecuteReader();
            lstGenric = new List<Object>();
            Type theType = objectClass.GetType();
            PropertyInfo[] p = theType.GetProperties();
            MethodInfo m = theType.GetMethod("Clone");
            ConstructorInfo ci = theType.GetConstructor(Type.EmptyTypes);
            object cunInv = ci.Invoke(null);
            object newObject = null;
            object[] custAttr = null;
            while (sqlDataReader.Read())
            {
                newObject = m.Invoke(cunInv, null);
                foreach (PropertyInfo pi in p)
                {
                    try
                    {
                        custAttr = pi.GetCustomAttributes(true);
                        if ((sqlDataReader[pi.Name] != System.DBNull.Value) && (custAttr.Length == 0))
                            pi.SetValue(newObject, sqlDataReader[pi.Name], null);
                   }
                    catch (System.IndexOutOfRangeException) { }
                }
                lstGenric.Add(newObject);
            }                      
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (sqlDataReader.IsClosed == false)
                sqlDataReader.Close();
            if (sqlConnection.State == ConnectionState.Open)
                sqlConnection.Close();
            sqlConnection.Dispose();
        }
        return lstGenric;
    }

Download Source code to see the worked out example.