Convert IEnumerable to DataTable

By Peter Bromberg

One of the problems with converting an IEnumerable to DataTable is the slowness of the reflection required. Here is a better way.

public static DataTable ToDataTable<T>(this IEnumerable<T> items)
    where T: class
{  

   DataTable table = new DataTable(typeof(T).Name);
       object[] a_oValues;
        int i;


    var propGetters = new List<Func<T, object>>();
foreach (var prop in props)
    {
        Func<T, object> func = (Func<T, object>) ReflectionUtility.GetGetter(prop);
         propGetters.Add(func);
    }

    // Add the property values per T as rows to the datatable
    foreach (var item in items)
    {  
         var values = new object[props.Length];  
        for (var i = 0; i < props.Length; i++)
        {
             //values[i] = props[i].GetValue(item, null);  
            values[i] = propGetters[i](item);
        }     

         table.Rows.Add(values);  
    }

     return table;
}


public class ReflectionUtility
{
    internal static Func<object, object> GetGetter(PropertyInfo property)
    {
         // get the get method for the property
       MethodInfo method = property.GetGetMethod(true);

        // get the generic get-method generator (ReflectionUtility.GetSetterHelper<TTarget, TValue>)
       MethodInfo genericHelper = typeof(ReflectionUtility).GetMethod(
             "GetGetterHelper",
           BindingFlags.Static | BindingFlags.NonPublic);

        // reflection call to the generic get-method generator to generate the type arguments
       MethodInfo constructedHelper = genericHelper.MakeGenericMethod(
            method.DeclaringType,
            method.ReturnType);

        // now call it. The null argument is because it's a static method.
        object ret = constructedHelper.Invoke(null, new object[] { method });

        // cast the result to the action delegate and return it
        return (Func<object, object>) ret;
    }

    static Func<object, object> GetGetterHelper<TTarget, TResult>(MethodInfo method)
        where TTarget : class // target must be a class as property sets on structs need a ref param
    {
         // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        Func<TTarget, TResult> func = (Func<TTarget, TResult>) Delegate.CreateDelegate(typeof(Func<TTarget, TResult>), method);

         // Now create a more weakly typed delegate which will call the strongly typed one
        Func<object, object> ret = (object target) => (TResult) func((TTarget) target);
         return ret;
    }
}

Convert IEnumerable to DataTable  (1999 Views)