使用反射和動態生成代碼兩種方式(Reflect和Emit) 反射將DataTable轉為List方法 1 public static List<T> ToListByReflect<T>(this DataTable dt) where T : new() 2 { 3 List<T> ts = ne ...
使用反射和動態生成代碼兩種方式(Reflect和Emit)
反射將DataTable轉為List方法
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 foreach (DataRow dr in dt.Rows) 6 { 7 T t = new T(); 8 PropertyInfo[] propertys = t.GetType().GetProperties(); 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個屬性)
電腦比較渣,使用Emit方法轉換100w條數據大概需要7秒,而反射則需要37秒。還測試了當數據量比較小時,Reflect反而比較快。