IDataReader/DataTable扩展ToList<T> 改进版,反射速度慢的惊人!

完整源代码购买:http://livexy.taobao.com/

IDataReader扩展ToList<T> 改进版


        
//最快和直接循环差不多
        public static List<TResult> ToList<TResult>(this IDataReader dr, bool isClose) where TResult : classnew() {
            IDataReaderEntityBuilder
<TResult> eblist = IDataReaderEntityBuilder<TResult>.CreateBuilder(dr);
            List
<TResult> list = new List<TResult>();
            
if (dr == nullreturn list;
            
while (dr.Read()) list.Add(eblist.Build(dr));
            
if (isClose) { dr.Close(); dr.Dispose(); dr = null; }
            
return list;
        }
        
public static List<TResult> ToList<TResult>(this IDataReader dr) where TResult : classnew() {
            
return dr.ToList<TResult>(true);
        }

        
//也慢
        public static List<TResult> ToList2<TResult>(this IDataReader dr, bool isClose) where TResult : classnew() {
            List<TResult> oblist = new List<TResult>();
            
if (dr == nullreturn oblist;

            List
<string> drColumns = new List<string>();
            
int len = dr.FieldCount;
            
for (int j = 0; j < len; j++) drColumns.Add(dr.GetName(j).Trim());
            

            List<PropertyInfo> prlist = new List<PropertyInfo>();
            Type t = typeof(TResult);
            Array.ForEach<PropertyInfo>(t.GetPropertiesCache(), p => { if (drColumns.IndexOf(p.Name) != -1) prlist.Add(p); });

            
while (dr.Read()) {
                TResult ob = new TResult();
                prlist.ForEach(p => { if (dr[p.Name] != DBNull.Value) p.SetValue(ob, dr[p.Name], null); });
                oblist.Add(ob);
            }
            
if (isClose) { dr.Close(); dr.Dispose(); dr = null; }
            
return oblist;
        }
        
public static List<TResult> ToList2<TResult>(this IDataReader dr) where TResult : classnew() {
            
return dr.ToList2<TResult>(true);
        }

        
//最慢
        public static List<TResult> ToList3<TResult>(this IDataReader dr, bool isClose) where TResult : classnew() {
            List
<TResult> list = new List<TResult>();
            
if (dr == nullreturn list;
            
int len = dr.FieldCount;

            
while (dr.Read()) {
                TResult info 
= new TResult();
                
for (int j = 0; j < len; j++) {
                    
if (dr[j] == null || string.IsNullOrEmpty(dr[j].ToString())) continue;
                    info.GetType().GetPropertyCache(dr.GetName(j).Trim()).SetValue(info, dr[j], 
null);
                }
                list.Add(info);
            }
            
if (isClose) { dr.Close(); dr.Dispose(); dr = null; }
            
return list;
        }
        
public static List<TResult> ToList3<TResult>(this IDataReader dr) where TResult : classnew() {
            
return dr.ToList3<TResult>(true);
        }

 

谢谢"幸运草"提供更快速的DataReader转实体LIST的代码.我将发在这里:

    public class IDataReaderEntityBuilder<Entity> {
        
private static readonly MethodInfo getValueMethod =
        
typeof(IDataRecord).GetMethod("get_Item"new Type[] { typeof(int) });
        
private static readonly MethodInfo isDBNullMethod =
            
typeof(IDataRecord).GetMethod("IsDBNull"new Type[] { typeof(int) });
        
private delegate Entity Load(IDataRecord dataRecord);

        
private Load handler;
        
private IDataReaderEntityBuilder() { }
        
public Entity Build(IDataRecord dataRecord) {
            
return handler(dataRecord);
        }
        
public static IDataReaderEntityBuilder<Entity> CreateBuilder(IDataRecord dataRecord) {
            IDataReaderEntityBuilder
<Entity> dynamicBuilder = new IDataReaderEntityBuilder<Entity>();
            DynamicMethod method 
= new DynamicMethod("DynamicCreateEntity"typeof(Entity),
                    
new Type[] { typeof(IDataRecord) }, typeof(Entity), true);
            ILGenerator generator 
= method.GetILGenerator();
            LocalBuilder result 
= generator.DeclareLocal(typeof(Entity));
            generator.Emit(OpCodes.Newobj, 
typeof(Entity).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc, result);
            
for (int i = 0; i < dataRecord.FieldCount; i++) {
                PropertyInfo propertyInfo 
= typeof(Entity).GetProperty(dataRecord.GetName(i));
                Label endIfLabel 
= generator.DefineLabel();
                
if (propertyInfo != null && propertyInfo.GetSetMethod() != null) {
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                    generator.Emit(OpCodes.Brtrue, endIfLabel);
                    generator.Emit(OpCodes.Ldloc, result);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValueMethod);
                    generator.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                    generator.MarkLabel(endIfLabel);
                }
            }
            generator.Emit(OpCodes.Ldloc, result);
            generator.Emit(OpCodes.Ret);
            dynamicBuilder.handler 
= (Load)method.CreateDelegate(typeof(Load));
            
return dynamicBuilder;
        }
    }

 

使用反射的同志们,请放泣使用反射方法转实体类LIST.

 

DataTable扩展ToList<T> 改进版


        
//最快和直接循环差不多
        public static List<TResult> ToList<TResult>(this DataTable dt) where TResult : classnew() {
            List
<TResult> list = new List<TResult>();
            
if (dt == nullreturn list;
            DataTableEntityBuilder
<TResult> eblist = DataTableEntityBuilder<TResult>.CreateBuilder(dt.Rows[0]);
            
foreach(DataRow info in dt.Rows) list.Add(eblist.Build(info));
            dt.Dispose(); dt 
= null;
            
return list;
        }

        
//也慢
        public static List<TResult> ToList2<TResult>(this DataTable dt) where TResult : classnew() { 
            List<PropertyInfo> prlist = new List<PropertyInfo>();
            Type t = typeof(TResult);
            Array.ForEach<PropertyInfo>(t.GetPropertiesCache(), p => { if (dt.Columns.IndexOf(p.Name) != -1) prlist.Add(p); });
            List<TResult> oblist = new List<TResult>();

            
foreach (DataRow row in dt.Rows) {
                TResult ob = new TResult();
                prlist.ForEach(p => { if (row[p.Name] != DBNull.Value) p.SetValue(ob, row[p.Name], null); });
                oblist.Add(ob);
            }
            
return oblist;
        }

        
//最慢
        public static List<TResult> ToList3<TResult>(this DataTable dt) where TResult : classnew() {
            List
<TResult> list = new List<TResult>();
            
if (dt == nullreturn list;
            
int len = dt.Rows.Count;

            
for (int i = 0; i < len; i++) {
                TResult info 
= new TResult();
                
foreach (DataColumn dc in dt.Rows[0].Table.Columns) {
                    
if (dt.Rows[i][dc.ColumnName] == null || string.IsNullOrEmpty(dt.Rows[i][dc.ColumnName].ToString())) continue;
                    info.GetType().GetPropertyCache(dc.ColumnName).SetValue(info, dt.Rows[i][dc.ColumnName], 
null);
                }
                list.Add(info);
            }
            dt.Dispose(); dt 
= null;
            
return list;
        }
    public class DataTableEntityBuilder<Entity> {
        
private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item"new Type[] { typeof(int) });
        
private static readonly MethodInfo isDBNullMethod = typeof(DataRow).GetMethod("IsNull"new Type[] { typeof(int) });
        
private delegate Entity Load(DataRow dataRecord);

        
private Load handler;
        
private DataTableEntityBuilder() { }

        
public Entity Build(DataRow dataRecord) {
            
return handler(dataRecord);
        }
        
public static DataTableEntityBuilder<Entity> CreateBuilder(DataRow dataRecord) {
            DataTableEntityBuilder
<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>();
            DynamicMethod method 
= new DynamicMethod("DynamicCreateEntity"typeof(Entity), new Type[] { typeof(DataRow) }, typeof(Entity), true);
            ILGenerator generator 
= method.GetILGenerator();
            LocalBuilder result 
= generator.DeclareLocal(typeof(Entity));
            generator.Emit(OpCodes.Newobj, 
typeof(Entity).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc, result);

            
for (int i = 0; i < dataRecord.ItemArray.Length; i++) {
                PropertyInfo propertyInfo 
= typeof(Entity).GetProperty(dataRecord.Table.Columns[i].ColumnName);
                Label endIfLabel 
= generator.DefineLabel();
                
if (propertyInfo != null && propertyInfo.GetSetMethod() != null) {
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                    generator.Emit(OpCodes.Brtrue, endIfLabel);
                    generator.Emit(OpCodes.Ldloc, result);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValueMethod);
                    generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                    generator.MarkLabel(endIfLabel);
                }
            }
            generator.Emit(OpCodes.Ldloc, result);
            generator.Emit(OpCodes.Ret);
            dynamicBuilder.handler 
= (Load)method.CreateDelegate(typeof(Load));
            
return dynamicBuilder;
        }
    }

 

 

 公司招人借主页用一天

1、大专以上学历,三年以上C#.NET/JS/CSS开发经验;
2、两年以上大型软件系统架构设计经验,二年以上项目管理经验优先;
3、精通SQL Server数据库,有海量数据处理经验优先;
4、有独立开发网站经验,能熟练使用jquery/ajax/json优先;
5、有作品,精通js/css,能熟练写DIV+CSS HTML代码,会使用dw/ps拆分图片优先;
6、良好的沟通、表达及分析能力,有团队合作精神,有学习新知识的渴望和优秀的学习能力。

欢迎加入我们,请投简历:

 http://job.cnblogs.com/offer/8966/

 

标签: ToList
posted @ 2010-09-01 22:27 熊哥 阅读(2794) 评论(23) 编辑 收藏

 回复 引用 查看   
#1楼[楼主]2010-09-01 22:51 | 熊哥      
欢迎加入我们的团队:)
 回复 引用 查看   
#2楼2010-09-02 08:10 | Artech      
Emit是个好东西。
 回复 引用 查看   
#3楼2010-09-02 08:38 | 兴说:      
说什么反射慢,没缓存没优化...每次都反射,吃饱了撑的。
 回复 引用 查看   
#4楼2010-09-02 08:46 | 幸运草      
引用兴说::说什么反射慢,没缓存没优化...每次都反射,吃饱了撑的。

不管你怎么优化在效率上都不能和 Emit 相提并论

 回复 引用 查看   
#5楼2010-09-02 08:53 | zeus2      
多慢 如果执行需要100ms几乎不用考虑 如果100个循环只用5ms 可以接受,因为这点时间对于现在的电脑可以忽略不计
 回复 引用 查看   
#6楼2010-09-02 08:58 | 黑色      
你们公司招人这要求也太高了吧,什么都要会。。。
 回复 引用 查看   
#7楼[楼主]2010-09-02 09:10 | 熊哥      
引用黑色:你们公司招人这要求也太高了吧,什么都要会。。。

不是都要会,是会的优先。当然也和工资相关的。

 回复 引用 查看   
#8楼[楼主]2010-09-02 09:12 | 熊哥      
引用zeus2:多慢 如果执行需要100ms几乎不用考虑 如果100个循环只用5ms 可以接受,因为这点时间对于现在的电脑可以忽略不计


DataReader使用反射转90W条记录需要19MS,加CACHE也需要15MS,使用Emit和直接循环都只需要3到4MS,相差太远.

 回复 引用 查看   
#9楼2010-09-02 09:53 | 金色海洋(jyk)      
看来真的是落伍了,这些代码都看不懂了。
 回复 引用 查看   
#10楼2010-09-02 10:23 | builderman      
在我电脑上需要把这句
PropertyInfo propertyInfo = typeof (T).GetProperty(dataRecord.GetName(i));

改成
PropertyInfo propertyInfo = typeof (T).GetProperty(dataRecord.GetName(i),
                                                                   BindingFlags.IgnoreCase | BindingFlags.Public |
                                                                   BindingFlags.Instance);

不然propertyInfo的值老是为null,不知道你们的是不是

另外,这样改后,string类型的字段都可以正确取到值,但是int型的字段取回来的确是一个很大的数字,不知道为什么

 回复 引用 查看   
#11楼2010-09-02 11:22 | 幸运草      
你的职位,俺非常适合,但俺去不了,呵呵
 回复 引用 查看   
#12楼2010-09-02 13:13 | Eric Fine      
说白了,这类应用反射最终是慢在 PropertyInfo.GetValue/SetValue 方法上.

纯用反射会要比直接访问属性慢100百以上.
用Expression包装的PropertyInfo.GetValue/SetValue包装到FastProperty类里比直接访问属性慢1-2倍左右.
用TEntity的Type为键缓存FastProperty到Dictionary<>里, 就更慢了,在Dicionary里检查再取出结果要花不少时间(相对花费).
最终方案要比直接写代码生成TEntity慢10倍.





 回复 引用 查看   
#13楼[楼主]2010-09-02 13:56 | 熊哥      
引用幸运草:你的职位,俺非常适合,但俺去不了,呵呵

呵呵,谢谢关注 :),有空到我这儿来玩.

 回复 引用 查看   
#14楼2010-09-02 16:10 | DYStudio.Net      
还好自己开过一辆机动三轮车,还是在农村的时候,记得三轮车都有一个一档,二档,三档...
挂一档跑呢,速度非常的慢,但是爬个坡什么的你难道用三档?
反射也如此.

 回复 引用 查看   
#15楼2010-09-02 20:43 | Alex He      
熊哥,熊哥
 回复 引用 查看   
#16楼[楼主]2010-09-02 20:49 | 熊哥      
引用Alex He:熊哥,熊哥

:)

 回复 引用 查看   
#17楼2010-09-03 13:00 | Zhenway      
也来show一个
http://www.cnblogs.com/vwxyzh/archive/2009/11/12/1601724.html
PS:你那里的工资比我现在的低,而且我还不满足要求,哈哈

 回复 引用 查看   
#18楼[楼主]2010-09-03 13:51 | 熊哥      
引用Zhenway:
也来show一个
http://www.cnblogs.com/vwxyzh/archive/2009/11/12/1601724.html
PS:你那里的工资比我现在的低,而且我还不满足要求,哈哈


呵呵没关系,希望你找个更好的。

 回复 引用 查看   
#19楼2010-09-03 14:20 | 《小YY》      
看具体情况用,如果什么都用这个 显然是不合适。
 回复 引用 查看   
#20楼[楼主]2010-09-03 15:47 | 熊哥      
引用《小YY》:看具体情况用,如果什么都用这个 显然是不合适。

用ToList不要用ToList2/ToList3
ToList性能还是很高的.

 回复 引用 查看   
#21楼2010-10-27 16:31 | zeus2      
这个Emit 如何改成支持int? 类型的?
 回复 引用 查看   
#22楼[楼主]2010-11-02 09:00 | 熊哥      
@zeus2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Data;
using System.Reflection;

namespace Pub.Class {
    public class IDataReaderEntityBuilder<Entity> {
        private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
        private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
        private delegate Entity Load(IDataRecord dataRecord);

        private Load handler;
        private IDataReaderEntityBuilder() { }

        public Entity Build(IDataRecord dataRecord) { return handler(dataRecord); }

        public static IDataReaderEntityBuilder<Entity> CreateBuilder(IDataRecord dataRecord) {
            IDataReaderEntityBuilder<Entity> dynamicBuilder = new IDataReaderEntityBuilder<Entity>();
            DynamicMethod method = new DynamicMethod("IDataReaderDynamicCreateEntity", typeof(Entity), new Type[] { typeof(IDataRecord) }, typeof(Entity), true);
            ILGenerator generator = method.GetILGenerator();
            LocalBuilder result = generator.DeclareLocal(typeof(Entity));
            generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc, result);

            for (int i = 0; i < dataRecord.FieldCount; i++) {
                PropertyInfo propertyInfo = typeof(Entity).GetProperty(dataRecord.GetName(i));
                Label endIfLabel = generator.DefineLabel();
                if (propertyInfo != null && propertyInfo.GetSetMethod() != null) {
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                    generator.Emit(OpCodes.Brtrue, endIfLabel);
                    generator.Emit(OpCodes.Ldloc, result);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValueMethod);
                    generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                    generator.MarkLabel(endIfLabel);
                }
            }
            generator.Emit(OpCodes.Ldloc, result);
            generator.Emit(OpCodes.Ret);
            dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
            return dynamicBuilder;
        }
    }
}


 回复 引用 查看   
#23楼2011-09-18 11:24 | [秦时明月]      
楼主,你的代码能以MIT协议形式使用吗?