How do I use reflection to dynamically call a type?

Viewed 63

I have a DataGrid and I need to convert it to a DataTable. The problem is that I need To be able to get the type of my DataSource dynamically. The grid DataSource is of type 'Observable' which is a class I have in my project, but my task is to be able to dynamically create the DataTable without needing to specify the type only using the DataSource. How can I generate a method that I can use to place in <T> without getting the error " 'mytype' is a variable but is used like a type" .

Type mytype = Grid_Job.DataSource.GetType();

DataTable dt = CreateDataTable<mytype>((IEnumerable<mytype>)Grid_Job.DataSource);

public static DataTable CreateDataTable<T>(IEnumerable<T> list)
        {
            Type type = typeof(T);
            var properties = type.GetProperties();

            DataTable dataTable = new DataTable();
            foreach (PropertyInfo info in properties)
            {
                dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
            }

            foreach (T entity in list)
            {
                object[] values = new object[properties.Length];
                for (int i = 0; i < properties.Length; i++)
                {
                    values[i] = properties[i].GetValue(entity);
                }

                dataTable.Rows.Add(values);
            }

            return dataTable;
        }

My Observable class is

public class Observable 
{
    public int JobNo { get; set; }
    public string JobName { get; set; }
    public string JobDescription { get; set; }
    public string Job_Type { get; set; }
    public string Job_Status { get; set; }
}
1 Answers

Effectively, you need to discard the generics and think in terms of the collection at runtime - discovering the element type itself. For example:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Reflection;

static class P
{
    static object GetData()
        => new ObservableCollection<Observable>
        {
            new Observable { JobName = "abc", JobNo = 123 },
            new Observable { JobName = "def", JobNo = 456 },
            new Observable { JobName = "ghi", JobNo = 789 },
        };
    static void Main()
    {
        // note that we don't know *anything* about the data source here
        object dataSource = GetData();
        DataTable dt = CreateDataTable((IEnumerable)dataSource);

        foreach (DataColumn col in dt.Columns)
        {
            Console.Write(col.ColumnName);
            Console.Write("\t");
        }
        Console.WriteLine();
        foreach (DataRow row in dt.Rows)
        {
            foreach (DataColumn col in dt.Columns)
            {
                Console.Write(row[col]);
                Console.Write("\t");
            }
            Console.WriteLine();
        }
    }

    public static DataTable CreateDataTable(IEnumerable list)
    {
        Type type = GetElementType(list.GetType());
        var properties = type.GetProperties();

        DataTable dataTable = new DataTable();
        foreach (PropertyInfo info in properties)
        {
            dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
        }

        object[] values = new object[properties.Length];
        foreach (object entity in list)
        {   
            for (int i = 0; i < properties.Length; i++)
            {
                values[i] = properties[i].GetValue(entity);
            }
            dataTable.Rows.Add(values);
        }
        return dataTable;
    }
    static Type GetElementType(Type type)
    {
        foreach (Type interfaceType in type.GetInterfaces())
        {
            if (interfaceType.IsGenericType &&
                interfaceType.GetGenericTypeDefinition()
                == typeof(IList<>))
            {
                return  type.GetGenericArguments()[0];
            }
        }
        return null;
    }
}
public class Observable
{
    public int JobNo { get; set; }
    public string JobName { get; set; }
    public string JobDescription { get; set; }
    public string Job_Type { get; set; }
    public string Job_Status { get; set; }
}

Note that in some cases you should prefer the TypeDescriptor model over reflection, as this allows runtime definition of properties; this is a niche area and probably doesn't apply to you, but it relevant to know about. As an example, this is how DataTable itself chooses to expose the properties it has as discoverable at runtime to general purpose tools. There are also a few list indirection APIs that need to be considered in those cases.

Related