Example #1
0
 internal static RowMap GetTypeMap(Type mType)
 {
     if (!XCache.TypeMaps.TryGetValue(mType, out var map))
     {
         map = new RowMap(mType);
         XCache.TypeMaps[mType] = map;
     }
     return(map);
 }
Example #2
0
        private static Func <IDataReader, M> SetFunc(IDataReader reader)
        {
            //
            var mType = typeof(M);
            var dm    = new DynamicMethod("MyDAL" + Guid.NewGuid().ToString(), mType, new[] { typeof(IDataReader) }, mType, true);
            var il    = dm.GetILGenerator();

            il.DeclareLocal(typeof(int)); // 定义 loc0  int
            il.DeclareLocal(mType);       //  定义 loc1 M
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Stloc_0);     //  赋值 loc0 = 0

            //
            var length  = reader.FieldCount;
            var names   = Enumerable.Range(0, length).Select(i => reader.GetName(i)).ToArray();
            var typeMap = CommonIL.GetTypeMap(mType);
            int index   = 0;
            var ctor    = typeMap.DefaultConstructor();

            //
            il.Emit(OpCodes.Newobj, ctor);
            il.Emit(OpCodes.Stloc_1);   //  赋值 loc1 = new M();
            il.BeginExceptionBlock();   //  try begin
            il.Emit(OpCodes.Ldloc_1);   //   加载 loc1

            //
            var  members          = names.Select(n => typeMap.GetMember(n)).ToList();
            bool first            = true;
            var  allDone          = il.DefineLabel();
            int  enumDeclareLocal = -1;
            int  valueCopyLocal   = il.DeclareLocal(typeof(object)).LocalIndex; // 定义 loc_object 变量, 然后返回此本地变量的index值, 其实就是截止目前, 定义了本地变量的个数

            foreach (var item in members)
            {
                if (item != null)
                {
                    il.Emit(OpCodes.Dup);
                    Label isDbNullLabel = il.DefineLabel();
                    Label finishLabel   = il.DefineLabel();

                    il.Emit(OpCodes.Ldarg_0);
                    CommonIL.EmitInt32(il, index);
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Stloc_0);
                    il.Emit(OpCodes.Callvirt, XConfig.GetItem);   //  获取reader读取的值, reader[index]
                    il.Emit(OpCodes.Dup);
                    CommonIL.StoreLocal(il, valueCopyLocal);      //  将 reader[index]的值, 存放到本地变量 loc_object 中
                    Type colType    = reader.GetFieldType(index); // reader[index] 的列的类型  source
                    Type memberType = item.MemberType();          //  M[item] 的类型

                    if (memberType == XConfig.TC.Char || memberType == XConfig.TC.CharNull)
                    {
                        il.EmitCall(
                            OpCodes.Call,
                            typeof(CommonIL).GetMethod(
                                memberType == XConfig.TC.Char
                                ? nameof(CommonIL.ReadChar)
                                : nameof(CommonIL.ReadNullableChar), BindingFlags.Static | BindingFlags.NonPublic),
                            null);
                    }
                    else
                    {
                        il.Emit(OpCodes.Dup);
                        il.Emit(OpCodes.Isinst, typeof(DBNull));    //  判断是否为DBNull类型, 如果是, 则跳转到 标签isDbNullLabel
                        il.Emit(OpCodes.Brtrue_S, isDbNullLabel);

                        var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
                        var unboxType          = nullUnderlyingType?.IsEnum == true ? nullUnderlyingType : memberType;

                        if (unboxType.IsEnum)
                        {
                            Type numericType = Enum.GetUnderlyingType(unboxType);
                            if (colType == typeof(string))
                            {
                                if (enumDeclareLocal == -1)
                                {
                                    enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex;
                                }
                                il.Emit(OpCodes.Castclass, typeof(string));                                              // stack is now [target][target][string]
                                CommonIL.StoreLocal(il, enumDeclareLocal);                                               // stack is now [target][target]
                                il.Emit(OpCodes.Ldtoken, unboxType);                                                     // stack is now [target][target][enum-type-token]
                                il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)), null); // stack is now [target][target][enum-type]
                                CommonIL.LoadLocal(il, enumDeclareLocal);                                                // stack is now [target][target][enum-type][string]
                                il.Emit(OpCodes.Ldc_I4_1);                                                               // stack is now [target][target][enum-type][string][true]
                                il.EmitCall(OpCodes.Call, XConfig.EnumParse, null);                                      // stack is now [target][target][enum-as-object]
                                il.Emit(OpCodes.Unbox_Any, unboxType);                                                   // stack is now [target][target][typed-value]
                            }
                            else
                            {
                                CommonIL.FlexibleConvertBoxedFromHeadOfStack(il, colType, unboxType, numericType);
                            }

                            if (nullUnderlyingType != null)
                            {
                                il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); // stack is now [target][target][typed-value]
                            }
                        }
                        else if (memberType.FullName == XConfig.TC.LinqBinary)
                        {
                            il.Emit(OpCodes.Unbox_Any, typeof(byte[]));                                        // stack is now [target][target][byte-array]
                            il.Emit(OpCodes.Newobj, memberType.GetConstructor(new Type[] { typeof(byte[]) })); // stack is now [target][target][binary]
                        }
                        else
                        {
                            TypeCode dataTypeCode = Type.GetTypeCode(colType), unboxTypeCode = Type.GetTypeCode(unboxType);
                            if (colType == unboxType || dataTypeCode == unboxTypeCode || dataTypeCode == Type.GetTypeCode(nullUnderlyingType))
                            {
                                il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value]
                            }
                            else
                            {
                                // not a direct match; need to tweak the unbox
                                CommonIL.FlexibleConvertBoxedFromHeadOfStack(il, colType, nullUnderlyingType ?? unboxType, null);
                                if (nullUnderlyingType != null)
                                {
                                    il.Emit(OpCodes.Newobj, unboxType.GetConstructor(new[] { nullUnderlyingType })); // stack is now [target][target][typed-value]
                                }
                            }
                        }
                    }
                    // Store the value in the property/field
                    if (item.Property != null)
                    {
                        il.Emit(OpCodes.Callvirt, RowMap.GetPropertySetter(item.Property, mType));
                    }
                    else
                    {
                        il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
                    }

                    il.Emit(OpCodes.Br_S, finishLabel); // stack is now [target]
                    il.MarkLabel(isDbNullLabel);        // incoming stack: [target][target][value]
                    il.Emit(OpCodes.Pop);               // stack is now [target][target]
                    il.Emit(OpCodes.Pop);               // stack is now [target]
                    il.MarkLabel(finishLabel);
                }
                first = false;
                index++;
            }

            il.Emit(OpCodes.Stloc_1);               // stack is empty
            il.MarkLabel(allDone);
            il.BeginCatchBlock(typeof(Exception));  // stack is Exception
            il.Emit(OpCodes.Ldloc_0);               // stack is Exception, index
            il.Emit(OpCodes.Ldarg_0);               // stack is Exception, index, reader
            CommonIL.LoadLocal(il, valueCopyLocal); // stack is Exception, index, reader, value
            il.EmitCall(OpCodes.Call, typeof(CommonIL).GetMethod(nameof(CommonIL.ThrowDataException)), null);
            il.EndExceptionBlock();

            il.Emit(OpCodes.Ldloc_1); // stack is [rval]
            il.Emit(OpCodes.Ret);

            var funcType = Expression.GetFuncType(typeof(IDataReader), mType);

            return((Func <IDataReader, M>)dm.CreateDelegate(funcType));
        }