大數據量下DataTable To List效率對比

使用反射和動態生成代碼兩種方式(Reflect和Emit)

反射將DataTable轉爲List方法ide

 1 public static List<T> ToListByReflect<T>(this DataTable dt) where T : new()
 2 {
 3     List<T> ts = new List<T>();
 4     string tempName = string.Empty;
 5     T t = new T();
 6     PropertyInfo[] propertys = t.GetType().GetProperties();
 7     foreach (DataRow dr in dt.Rows)
 8     {
 9         foreach (PropertyInfo pi in propertys)
10         {
11             tempName = pi.Name;
12             if (dt.Columns.Contains(tempName))
13             {
14                 object value = dr[tempName];
15                 if (value != DBNull.Value)
16                 {
17                     pi.SetValue(t, value, null);
18                 }
19             }
20         }
21         ts.Add(t);
22     }
23     return ts;
24 }
View Code

動態生成代碼將DataTable轉爲List方法測試

 1 public static List<T> ToListByEmit<T>(this DataTable dt) where T : class, new()
 2         {
 3             List<T> list = new List<T>();
 4             if (dt == null || dt.Rows.Count == 0)
 5                 return list;
 6             DataTableEntityBuilder<T> eblist = DataTableEntityBuilder<T>.CreateBuilder(dt.Rows[0]);
 7             foreach (DataRow info in dt.Rows)
 8                 list.Add(eblist.Build(info));
 9             dt.Dispose();
10             dt = null;
11             return list;
12         }
13         public class DataTableEntityBuilder<Entity>
14         {
15             private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item", new Type[] { typeof(int) });
16             private static readonly MethodInfo isDBNullMethod = typeof(DataRow).GetMethod("IsNull", new Type[] { typeof(int) });
17             private delegate Entity Load(DataRow dataRecord);
18             private Load handler;
19             private DataTableEntityBuilder() { }
20             public Entity Build(DataRow dataRecord)
21             {
22                 return handler(dataRecord);
23             }
24             public static DataTableEntityBuilder<Entity> CreateBuilder(DataRow dataRecord)
25             {
26                 DataTableEntityBuilder<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>();
27                 DynamicMethod method = new DynamicMethod("DynamicCreateEntity", typeof(Entity), new Type[] { typeof(DataRow) }, typeof(Entity), true);
28                 ILGenerator generator = method.GetILGenerator();
29                 LocalBuilder result = generator.DeclareLocal(typeof(Entity));
30                 generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
31                 generator.Emit(OpCodes.Stloc, result);
32                 for (int i = 0; i < dataRecord.ItemArray.Length; i++)
33                 {
34                     PropertyInfo propertyInfo = typeof(Entity).GetProperty(dataRecord.Table.Columns[i].ColumnName);
35                     Label endIfLabel = generator.DefineLabel();
36                     if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
37                     {
38                         generator.Emit(OpCodes.Ldarg_0);
39                         generator.Emit(OpCodes.Ldc_I4, i);
40                         generator.Emit(OpCodes.Callvirt, isDBNullMethod);
41                         generator.Emit(OpCodes.Brtrue, endIfLabel);
42                         generator.Emit(OpCodes.Ldloc, result);
43                         generator.Emit(OpCodes.Ldarg_0);
44                         generator.Emit(OpCodes.Ldc_I4, i);
45                         generator.Emit(OpCodes.Callvirt, getValueMethod);
46                         generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
47                         generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
48                         generator.MarkLabel(endIfLabel);
49                     }
50                 }
51                 generator.Emit(OpCodes.Ldloc, result);
52                 generator.Emit(OpCodes.Ret);
53                 dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
54                 return dynamicBuilder;
55             }
56         }
View Code

而後寫個控制檯程序,對比一下兩個方法的效率(測試類大概有40個屬性)ui

電腦比較渣,使用Emit方法轉換100w條數據大概須要7秒,而反射則須要37秒。還測試了當數據量比較小時,Reflect反而比較快。this

相關文章
相關標籤/搜索