高效 IEnumerable<T>转DataTable

IEnumerable<T>中的T是泛型,咱们就不能事先知道T都有哪些属性,因此创建出来的DataTable也就不能预先设置列。遇到这种情况,首先就想到反射。

public static DataTable ToDataTable<T>(IEnumerable<T> collection)
{
    var props = typeof(T).GetProperties();
    var dt = new DataTable();
    dt.Columns.AddRange(props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray());
    if (collection.Count() > 0)
    {
        for (int i = 0; i < collection.Count(); i++)
        {
            ArrayList tempList = new ArrayList();
            foreach (PropertyInfo pi in props)
            {
                object obj = pi.GetValue(collection.ElementAt(i), null);
                tempList.Add(obj);
            }
            object[] array = tempList.ToArray();
            dt.LoadDataRow(array, true);
        }
    }
    return dt;
}

反射效率低,自然而然我们又想到了表达式树这个东西,表达式树的其中一个作用就是实现了反射的功能同时避免了反射带来的效率问题。

首先咱打算构造一个形如obj=>obj.Property的表达式树。

//构造委托类似Func<User, int> getAge = u => u.Age; 
static Func<T, object> GetGetDelegate<T>(PropertyInfo p)
{
    var param_obj = Expression.Parameter(typeof(T), "obj");
    //lambda的方法体 u.Age
    var pGetter = Expression.Property(param_obj, p);
    //编译lambda
    return Expression.Lambda<Func<T, object>>(pGetter, param_obj).Compile();
}

static object FastGetValue<T>(this PropertyInfo property, T t)
{
    return GetGetDelegate<T>(property)(t);
}

然后我们就可以将上述反射代码改成如下:

public static DataTable ToTable<T>(this IEnumerable<T> collection)
{
    var props = typeof(T).GetProperties();

    var dt = new DataTable();
    dt.Columns.AddRange(
        props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray()
    );

    collection.ToList().ForEach(
        i => dt.Rows.Add(props.Select(p => p.FastGetValue(i)).ToArray())
    );

    return dt;
}


很好,咱们没用到反射就把工作完成了。但是效率真的有提升吗?我看未必。后者只是将前者的pi.GetValue(collection.ElementAt(i), null)改成p => p.FastGetValue(i),而FastGetValue会每次都去构造表达式树然后编译Lambda,针对IEnumerable<T>中的每一条数据都重复构造相同的属性委托。两者效率我没测过,不过这个方式肯定不完美。改进的方式有很多,比如将属性和GetGetDelegate构造的委托作为键值对缓存起来供后续循环使用等等。下面是我想到的较好的一种解决方法:  

 static Func<T, object[]> GetGetDelegate<T>(PropertyInfo[] ps)
 {
     var param_obj = Expression.Parameter(typeof(T), "obj");
     Expression newArrayExpression = Expression.NewArrayInit(typeof(object), ps.Select(p => Expression.Property(param_obj, p)));
     return Expression.Lambda<Func<T, object[]>>(newArrayExpression, param_obj).Compile();
 }
public static DataTable ToTable<T>(this IEnumerable<T> collection)
{
    var props = typeof(T).GetProperties();
    var func = GetGetDelegate<T>(props);
    var dt = new DataTable();
    dt.Columns.AddRange(
        props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray()
    );
    collection.ToList().ForEach(i => dt.Rows.Add(func(i)));

    return dt;
}

转载请注明本文出处: http://www.cnblogs.com/newton/archive/2013/01/09/2853083.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值