/// <summary> /// 将DataTable数据转换为List数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="table"></param> /// <returns></returns> public static List <T> ToList <T>(this DataTable table, string suffix = "") where T : class, new() { if (table == null) { return(new List <T>()); } Type tType = typeof(T); Delegate del = null; if (!cache_del.TryGetValue(tType, out del)) { PropertyInfo[] pinfos = tType.GetProperties(); Dictionary <string, PropertyInfo> dic_p = new Dictionary <string, PropertyInfo>(); foreach (var p in pinfos) { DbParamterAttribute paramter_att = p.GetCustomAttribute <DbParamterAttribute>(); string keyName = p.Name; if (paramter_att != null && !string.IsNullOrEmpty(paramter_att.Name)) { keyName = paramter_att.Name; } if (dic_p.ContainsKey(keyName)) { throw new Exception(string.Format("列名映射关系重复:{0}", keyName)); } else { dic_p.Add(keyName, p); } } MethodInfo addMethod = typeof(List <T>).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public); DynamicMethod method = new DynamicMethod(tType.FullName, typeof(List <T>), new Type[] { typeof(DataTable), typeof(string) }, true); var gen = method.GetILGenerator(); LocalBuilder countBulider = gen.DeclareLocal(typeof(int)); LocalBuilder tableCountBulider = gen.DeclareLocal(typeof(int)); LocalBuilder rowBulider = gen.DeclareLocal(typeof(DataRow)); LocalBuilder resultBulider = gen.DeclareLocal(typeof(List <T>)); LocalBuilder newObjBulider = gen.DeclareLocal(tType); LocalBuilder columnBulider = gen.DeclareLocal(typeof(DataColumnCollection)); gen.Emit(OpCodes.Newobj, typeof(List <T>).GetConstructor(Type.EmptyTypes)); gen.Emit(OpCodes.Stloc, resultBulider.LocalIndex);//new List gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, ColumnsInfo.GetGetMethod()); gen.Emit(OpCodes.Stloc, columnBulider.LocalIndex); Dictionary <string, LocalBuilder> columnNameDic = new Dictionary <string, LocalBuilder>(); foreach (string k in dic_p.Keys) { if (!columnNameDic.ContainsKey(k)) { LocalBuilder rBulider = gen.DeclareLocal(typeof(string)); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Ldstr, k); gen.Emit(OpCodes.Call, StringConcat); gen.Emit(OpCodes.Stloc, rBulider.LocalIndex); columnNameDic.Add(k, rBulider); } } gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Stloc, countBulider.LocalIndex); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, RowsInfo.GetGetMethod()); gen.Emit(OpCodes.Call, CountInfo.GetGetMethod()); gen.Emit(OpCodes.Stloc, tableCountBulider.LocalIndex); Label eachLabel = gen.DefineLabel(); Label emptyLabel = gen.DefineLabel(); gen.Emit(OpCodes.Ldloc, tableCountBulider.LocalIndex); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Ble, emptyLabel); gen.MarkLabel(eachLabel);//循环顶部标签 LocalBuilder entityBulider = gen.DeclareLocal(typeof(T)); gen.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); gen.Emit(OpCodes.Stloc, entityBulider.LocalIndex); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldloc, countBulider.LocalIndex); gen.Emit(OpCodes.Call, m_get_row_define); gen.Emit(OpCodes.Stloc, rowBulider.LocalIndex); foreach (var item in columnNameDic) { var key = item.Key; var p = dic_p[key]; gen.Emit(OpCodes.Ldloc, entityBulider.LocalIndex); gen.Emit(OpCodes.Ldloc, rowBulider.LocalIndex); gen.Emit(OpCodes.Ldloc, item.Value.LocalIndex); gen.Emit(OpCodes.Call, m_get_row_Value.MakeGenericMethod(new Type[] { p.PropertyType })); gen.Emit(OpCodes.Call, p.GetSetMethod()); } gen.Emit(OpCodes.Ldloc, resultBulider.LocalIndex); gen.Emit(OpCodes.Ldloc, entityBulider.LocalIndex); gen.Emit(OpCodes.Call, addMethod); gen.Emit(OpCodes.Ldloc, countBulider.LocalIndex); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Add_Ovf); gen.Emit(OpCodes.Stloc, countBulider.LocalIndex); gen.Emit(OpCodes.Ldloc, countBulider.LocalIndex); gen.Emit(OpCodes.Ldloc, tableCountBulider.LocalIndex); //判断是否小于table.Rows.Count,是则调到循环顶部Label gen.Emit(OpCodes.Blt, eachLabel); gen.MarkLabel(emptyLabel); gen.Emit(OpCodes.Ldloc, resultBulider.LocalIndex); gen.Emit(OpCodes.Ret); del = method.CreateDelegate(typeof(ToTableList <T>)); cache_del.TryAdd(tType, del); } return((del as ToTableList <T>)(table, suffix)); }
/// <summary> /// 获取参数封装入集合 /// </summary> /// <param name="paramterList"></param> /// <param name="gen"></param> /// <param name="paramterListBulider"></param> private static void GetParamters(List <Tuple <string, int, MethodInfo, Type> > outputParamters, ParameterInfo[] paramterList, ILGenerator gen, LocalBuilder paramterListBulider, bool use_cache, string sqlTextKey, out ParameterInfo scope_parameterInfo) { scope_parameterInfo = null; bool haschache_attr = paramterList.Any(x => x.GetCustomAttribute <DbCacheKeyAttribute>() != null); foreach (var paramter in paramterList) { if (!string.IsNullOrEmpty(sqlTextKey) && paramter.Name == sqlTextKey) { //跳过指定sql语句的参数 continue; } Type pType = paramter.ParameterType; Type eType = pType.GetElementType();//若为ref或out参数则eType为其原来类型 if (pType.GetInterface(SCOPE_ITEM) != null || (eType != null && eType.GetInterface(SCOPE_ITEM) != null)) { //IDbNetScope类型为事务处理变量,不能添加到参数中 scope_parameterInfo = paramter; continue; } LocalBuilder pTypeBulider = null; DbNetParamterDirection dir = DbNetParamterDirection.Input; CacheKeyType cacheKeyType = CacheKeyType.None; if (use_cache) { cacheKeyType = CacheKeyType.Bind; if (haschache_attr) { cacheKeyType = CacheKeyType.None; } var cache_attr = paramter.GetCustomAttribute <DbCacheKeyAttribute>(); if (cache_attr != null) { cacheKeyType = CacheKeyType.Bind; } } if (!paramter.IsOut && !pType.IsByRef) { pTypeBulider = gen.DeclareLocal(pType); gen.Emit(OpCodes.Ldarg, paramter.Position + 1); } else { dir = DbNetParamterDirection.InputAndOutPut; pTypeBulider = gen.DeclareLocal(eType); if (pType.IsByRef) { //获取ref参数的值 gen.Emit(OpCodes.Ldarg, paramter.Position + 1); GetRef(gen, pTypeBulider.LocalType); } } gen.Emit(OpCodes.Stloc, pTypeBulider); if (pTypeBulider.LocalType.IsClass) { Label isNullLabel = gen.DefineLabel(); gen.Emit(OpCodes.Ldloc, pTypeBulider); gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Ceq); gen.Emit(OpCodes.Brfalse, isNullLabel); gen.Emit(OpCodes.Call, MethodHelper.defaultMethod.MakeGenericMethod(pTypeBulider.LocalType)); gen.Emit(OpCodes.Stloc, pTypeBulider); gen.MarkLabel(isNullLabel); } if (paramter.IsOut || pType.IsByRef) { //输出参数获取下阶段备用 outputParamters.Add(new Tuple <string, int, MethodInfo, Type>(paramter.Name, paramter.Position + 1, null, eType)); } if (pTypeBulider.LocalType == typeof(string) || pTypeBulider.LocalType.IsValueType || pTypeBulider.LocalType.IsArray) { //添加结构体或者string到集合 gen.Emit(OpCodes.Ldloc, paramterListBulider); gen.Emit(OpCodes.Ldstr, paramter.Name); gen.Emit(OpCodes.Ldloc, pTypeBulider); gen.Emit(OpCodes.Ldc_I4, (int)dir); gen.Emit(OpCodes.Ldc_I4, paramter.Position); gen.Emit(OpCodes.Ldc_I4, (int)SourceType.FromArg); gen.Emit(OpCodes.Ldc_I4, (int)cacheKeyType); gen.Emit(OpCodes.Call, MethodHelper.paramterMethod.MakeGenericMethod(pTypeBulider.LocalType)); } else { //如果参数是类则需进一步处理 var pinfo = pTypeBulider.LocalType.GetProperties(); var cache_attr_c = paramter.GetCustomAttribute <DbCacheKeyAttribute>(); foreach (var p in pinfo) { DbParamterAttribute attr_p = p.GetCustomAttribute <DbParamterAttribute>(true); bool except = false; string name = string.Empty; DbNetParamterDirection pdir = DbNetParamterDirection.Input; CacheKeyType p_cacheKeyType = CacheKeyType.None; if (use_cache) { p_cacheKeyType = CacheKeyType.Bind; if (haschache_attr) { p_cacheKeyType = CacheKeyType.None; } if (cache_attr_c != null) { p_cacheKeyType = CacheKeyType.Bind; } if (attr_p != null && attr_p.CacheKey != CacheKeyType.Default) { p_cacheKeyType = attr_p.CacheKey; } } if (paramter.IsOut) { //输出参数获取下阶段备用 outputParamters.Add(new Tuple <string, int, MethodInfo, Type>(paramter.Name, paramter.Position + 1, p.GetSetMethod(), p.PropertyType)); pdir = DbNetParamterDirection.Output; } else if (pType.IsByRef) { //输出参数获取下阶段备用 outputParamters.Add(new Tuple <string, int, MethodInfo, Type>(paramter.Name, paramter.Position + 1, p.GetSetMethod(), p.PropertyType)); pdir = DbNetParamterDirection.InputAndOutPut; } if (attr_p != null) { except = attr_p.Except; name = attr_p.Name; pdir = attr_p.ParameterDirection; } if (string.IsNullOrEmpty(name)) { name = p.Name; } if (!except) { gen.Emit(OpCodes.Ldloc, paramterListBulider); gen.Emit(OpCodes.Ldstr, name); gen.Emit(OpCodes.Ldloc, pTypeBulider); gen.Emit(OpCodes.Call, p.GetGetMethod()); gen.Emit(OpCodes.Ldc_I4, (int)pdir); gen.Emit(OpCodes.Ldc_I4, paramter.Position); gen.Emit(OpCodes.Ldc_I4, (int)SourceType.FromClass); gen.Emit(OpCodes.Ldc_I4, (int)p_cacheKeyType); gen.Emit(OpCodes.Call, MethodHelper.paramterMethod.MakeGenericMethod(p.PropertyType)); } } } } }