예제 #1
0
        public virtual Delegate CreateDelegate(Type sourceType, Type targetType, ModuleBuilder builder)
        {
            var typeBuilder   = builder.DefineStaticType();
            var methodBuilder = typeBuilder.DefineStaticMethod("Map");

            methodBuilder.SetParameters(sourceType, targetType);
            var il      = methodBuilder.GetILGenerator();
            var context = new CompilationContext(il);

            context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0));
            context.SetTarget(purpose => il.Emit(OpCodes.Ldarg_1));
            Emit(sourceType, targetType, context);
            context.Emit(OpCodes.Ret);
#if NetCore
            return(typeBuilder.CreateTypeInfo()
                   .GetMethod("Map", BindingFlags.Static | BindingFlags.Public)
                   .CreateDelegate(typeof(Action <,>).MakeGenericType(sourceType, targetType)));
#else
            return(Delegate.CreateDelegate(typeof(Action <,>).MakeGenericType(sourceType, targetType), typeBuilder.CreateType(), "Map"));
#endif
        }
예제 #2
0
        public virtual Delegate CreateDelegate(Type sourceType, Type targetType, ModuleBuilder builder)
        {
            var typeBuilder   = builder.DefineStaticType();
            var methodBuilder = typeBuilder.DefineStaticMethod("Convert");

            methodBuilder.SetReturnType(targetType);
            methodBuilder.SetParameters(sourceType);
            var il      = methodBuilder.GetILGenerator();
            var context = new CompilationContext(il);

            il.Emit(OpCodes.Ldarg_0);
            context.CurrentType = sourceType;
            Emit(sourceType, targetType, context);
            context.Emit(OpCodes.Ret);
#if NETSTANDARD
            return(typeBuilder.CreateTypeInfo()
                   .GetMethod("Convert", BindingFlags.Static | BindingFlags.Public)
                   .CreateDelegate(typeof(Func <,>).MakeGenericType(sourceType, targetType)));
#else
            return(Delegate.CreateDelegate(typeof(Func <,>).MakeGenericType(sourceType, targetType), typeBuilder.CreateType(), "Convert"));
#endif
        }
예제 #3
0
        public override void Emit(Type sourceType, Type targetType, CompilationContext context)
        {
#if NetCore
            var reflectingTargetType = targetType.GetTypeInfo();
#else
            var reflectingTargetType = targetType;
#endif
            var target = context.DeclareLocal(targetType);
            var local  = context.DeclareLocal(sourceType);
            context.Emit(OpCodes.Stloc, local);

            if (targetType.IsNullable())
            {
                var labelEnd   = context.DefineLabel();
                var labelFirst = context.DefineLabel();
                // if(source == null)
                context.Emit(OpCodes.Ldloc, local);
                context.Emit(OpCodes.Brtrue, labelFirst);

                // target = null;
                context.Emit(OpCodes.Ldloca, target);
                context.Emit(OpCodes.Initobj, targetType);

                // goto end;
                context.Emit(OpCodes.Br, labelEnd);
                context.MakeLabel(labelFirst);

                // if(string.IsNullOrWhiteSpace(source))
                var labelSecond = context.DefineLabel();
                context.Emit(OpCodes.Ldloc, local);
                context.EmitCall(_checkEmptyMethod);
                context.Emit(OpCodes.Brfalse, labelSecond);

                // target = new Nullable<T>(default(T));
                context.EmitDefault(reflectingTargetType.GetGenericArguments()[0]);
                context.Emit(OpCodes.Newobj, reflectingTargetType.GetConstructors()[0]);
                context.Emit(OpCodes.Stloc, target);

                // goto end;
                context.Emit(OpCodes.Br, labelEnd);
                context.MakeLabel(labelSecond);

                // target = new Nullable<$EnumType$>(($EnumType$)Enum.Parse(typeof($EnumType$),source));
                // or
                // target = new Nullable<$TargetType$>($TargetType$.Parse(source));
                var underlingType = reflectingTargetType.GetGenericArguments()[0];
#if NetCore
                if (underlingType.GetTypeInfo().IsEnum)
#else
                if (underlingType.IsEnum)
#endif
                {
                    context.EmitTypeOf(underlingType);
                }
                context.Emit(OpCodes.Ldloc, local);
                context.EmitCall(_stringTrimMethod);
                context.EmitCall(GetConvertMethod(underlingType));
                context.EmitCast(underlingType);
                context.Emit(OpCodes.Newobj, reflectingTargetType.GetConstructors()[0]);
                context.Emit(OpCodes.Stloc, target);

                context.MakeLabel(labelEnd);
                context.Emit(OpCodes.Ldloc, target);
            }
            else
            {
                // if(!string.IsNullOrWhiteSpace(source))
                var label = context.DefineLabel();
                context.Emit(OpCodes.Ldloc, local);
                context.EmitCall(_checkEmptyMethod);
                context.Emit(OpCodes.Brtrue, label);

                // target = ($EnumType$)Enum.Parse(typeof($EnumType$),source);
                // or
                // target = $TargetType$.Parse(source);
                if (reflectingTargetType.IsEnum)
                {
                    context.EmitTypeOf(targetType);
                }
                context.Emit(OpCodes.Ldloc, local);
                context.EmitCall(_stringTrimMethod);
                context.EmitCall(GetConvertMethod(targetType));
                context.EmitCast(targetType);
                context.Emit(OpCodes.Stloc, target);

                // goto end;
                var labelEnd = context.DefineLabel();
                context.Emit(OpCodes.Br, labelEnd);

                // target = default(T);
                context.MakeLabel(label);
                context.EmitDefault(targetType);
                context.Emit(OpCodes.Stloc, target);

                context.MakeLabel(labelEnd);
                context.Emit(OpCodes.Ldloc, target);
            }
        }
예제 #4
0
        public Action <TSource, TTarget> CreateMapper(ModuleBuilder builder)
        {
            Initialize();
            if (_customMapper != null)
            {
                return(_customMapper);
            }
            var typeBuilder   = builder.DefineStaticType();
            var methodBuilder = typeBuilder.DefineStaticMethod("Map");

            methodBuilder.SetReturnType(typeof(void));
            methodBuilder.SetParameters(typeof(TSource), typeof(TTarget));

#if NetCore
            var reflectingTargetType = typeof(TTarget).GetTypeInfo();
            var reflectingSourceType = typeof(TSource).GetTypeInfo();
#else
            var reflectingTargetType = typeof(TTarget);
            var reflectingSourceType = typeof(TSource);
#endif

            var il      = methodBuilder.GetILGenerator();
            var context = new CompilationContext(il);
            if (reflectingSourceType.IsValueType)
            {
                context.SetSource(purpose =>
                {
                    if (purpose == LoadPurpose.MemberAccess)
                    {
                        il.Emit(OpCodes.Ldarga_S, 0);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldarg_0);
                    }
                });
            }
            else
            {
                context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0));
            }
            if (reflectingTargetType.IsValueType)
            {
                context.SetTarget(purpose =>
                {
                    if (purpose == LoadPurpose.MemberAccess)
                    {
                        il.Emit(OpCodes.Ldarga_S, 1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldarg_1);
                    }
                });
            }
            else
            {
                context.SetTarget(purpose => il.Emit(OpCodes.Ldarg_1));
            }
            EmitMap(context);
            context.Emit(OpCodes.Ret);
#if NetCore
            return((Action <TSource, TTarget>)typeBuilder.CreateTypeInfo().GetMethod("Map", BindingFlags.Static | BindingFlags.Public).CreateDelegate(typeof(Action <TSource, TTarget>)));
#else
            return((Action <TSource, TTarget>)Delegate.CreateDelegate(typeof(Action <TSource, TTarget>), typeBuilder.CreateType(), "Map"));
#endif
        }
예제 #5
0
        public Func <TSource, TTarget> CreateConverter(ModuleBuilder builder)
        {
            Initialize();
            var typeBuilder   = builder.DefineStaticType();
            var methodBuilder = typeBuilder.DefineStaticMethod("Convert");

            methodBuilder.SetReturnType(typeof(TTarget));
            methodBuilder.SetParameters(typeof(TSource));
            ConverterMethod = methodBuilder;
#if NETSTANDARD
            var reflectingTargetType = typeof(TTarget).GetTypeInfo();
            var reflectingSourceType = typeof(TSource).GetTypeInfo();
#else
            var reflectingTargetType = typeof(TTarget);
            var reflectingSourceType = typeof(TSource);
#endif

            var il      = methodBuilder.GetILGenerator();
            var context = new CompilationContext(il);
            if (reflectingSourceType.IsValueType)
            {
                context.SetSource(purpose =>
                {
                    if (purpose == LoadPurpose.MemberAccess)
                    {
                        il.Emit(OpCodes.Ldarga_S, 0);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldarg_0);
                    }
                });
            }
            else
            {
                context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0));
            }
            var targetLocal = il.DeclareLocal(typeof(TTarget));
            _creator.Emit(context);
            il.Emit(OpCodes.Stloc, targetLocal);
            if (reflectingTargetType.IsValueType)
            {
                context.SetTarget(
                    purpose =>
                    il.Emit(purpose == LoadPurpose.MemberAccess ? OpCodes.Ldloca_S : OpCodes.Ldloc, targetLocal));
            }
            else
            {
                context.SetTarget(purpose => il.Emit(OpCodes.Ldloc, targetLocal));
            }
            EmitMap(context);
            context.LoadTarget(LoadPurpose.ReturnValue);
            context.Emit(OpCodes.Ret);
#if NETSTANDARD
            ConverterMethod = typeBuilder.CreateTypeInfo().GetMethod("Convert", BindingFlags.Static | BindingFlags.Public);
            return((Func <TSource, TTarget>)ConverterMethod.CreateDelegate(typeof(Func <TSource, TTarget>)));
#else
            ConverterMethod = typeBuilder.CreateType().GetMethod("Convert", BindingFlags.Static | BindingFlags.Public);
            return((Func <TSource, TTarget>)Delegate.CreateDelegate(typeof(Func <TSource, TTarget>), ConverterMethod));
#endif
        }
        public static void EmitCast(this CompilationContext context, Type targetType)
        {
            if (context.CurrentType == targetType)
            {
                return;
            }
#if NetCore
            var currentTypeIsValue = context.CurrentType.GetTypeInfo().IsValueType;
            var targetTypeIsValue  = targetType.GetTypeInfo().IsValueType;
#else
            var currentTypeIsValue = context.CurrentType.IsValueType;
            var targetTypeIsValue  = targetType.IsValueType;
#endif
            if (!currentTypeIsValue && targetTypeIsValue)
            {
                context.Emit(OpCodes.Unbox_Any, targetType);
            }
            else if (currentTypeIsValue && !targetTypeIsValue)
            {
                context.Emit(OpCodes.Box, context.CurrentType);
                if (targetType != typeof(object) && targetType != typeof(Enum) && targetType != typeof(void))
                {
                    context.Emit(OpCodes.Castclass, targetType);
                }
            }
            else
            {
                if (context.CurrentType == typeof(long) || context.CurrentType == typeof(ulong) ||
                    context.CurrentType == typeof(int) || context.CurrentType == typeof(uint) ||
                    context.CurrentType == typeof(short) || context.CurrentType == typeof(ushort) ||
                    context.CurrentType == typeof(byte) || context.CurrentType == typeof(sbyte) ||
                    context.CurrentType == typeof(float) || context.CurrentType == typeof(double) ||
                    context.CurrentType == typeof(char) || context.CurrentType == typeof(bool))
                {
                    if (targetType == typeof(sbyte))
                    {
                        context.Emit(OpCodes.Conv_I1);
                    }
                    if (targetType == typeof(byte))
                    {
                        context.Emit(OpCodes.Conv_U1);
                    }
                    if (targetType == typeof(short) || targetType == typeof(char))
                    {
                        context.Emit(OpCodes.Conv_I2);
                    }
                    if (targetType == typeof(ushort))
                    {
                        context.Emit(OpCodes.Conv_U2);
                    }
                    if (targetType == typeof(int))
                    {
                        context.Emit(OpCodes.Conv_I4);
                    }
                    if (targetType == typeof(uint))
                    {
                        context.Emit(OpCodes.Conv_U4);
                    }
                    if (targetType == typeof(long))
                    {
                        context.Emit(OpCodes.Conv_I8);
                    }
                    if (targetType == typeof(ulong))
                    {
                        context.Emit(OpCodes.Conv_U8);
                    }
                    if (targetType == typeof(float))
                    {
                        context.Emit(OpCodes.Conv_R4);
                    }
                    if (targetType == typeof(double))
                    {
                        context.Emit(OpCodes.Conv_R8);
                    }
                }
                else if (currentTypeIsValue)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.Emit_InvalidCastType, context.CurrentType, targetType));
                }
                else if (targetType != typeof(object))
                {
                    context.Emit(OpCodes.Castclass, targetType);
                }
            }
            context.CurrentType = targetType;
        }
 public static void EmitTypeOf(this CompilationContext context, Type targetType)
 {
     context.Emit(OpCodes.Ldtoken, targetType);
     context.Emit(OpCodes.Call, _getTypeFromHandleMethod);
 }
 public static void EmitCall(this CompilationContext context, MethodInfo method)
 {
     context.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method);
     context.CurrentType = method.ReturnType;
 }
        public static void EmitDefault(this CompilationContext context, Type targetType)
        {
            var originalType = targetType;

            if (targetType.IsNullable())
            {
                var local = context.DeclareLocal(targetType);
                context.Emit(OpCodes.Ldloca, local);
                context.Emit(OpCodes.Initobj, targetType);
                context.Emit(OpCodes.Ldloc, local);
                context.CurrentType = originalType;
                return;
            }
#if NetCore
            if (!targetType.GetTypeInfo().IsValueType)
#else
            if (!targetType.IsValueType)
#endif
            {
                context.Emit(OpCodes.Ldnull);
                context.CurrentType = originalType;
                return;
            }
#if NetCore
            if (targetType.GetTypeInfo().IsEnum)
#else
            if (targetType.IsEnum)
#endif
            {
                targetType = Enum.GetUnderlyingType(targetType);
            }
            if (targetType == typeof(int) || targetType == typeof(uint) ||
                targetType == typeof(short) || targetType == typeof(ushort) ||
                targetType == typeof(byte) || targetType == typeof(sbyte) ||
                targetType == typeof(char) || targetType == typeof(bool))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.CurrentType = originalType;
                return;
            }
            if (targetType == typeof(long) || targetType == typeof(ulong))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.Emit(OpCodes.Conv_I8);
                context.CurrentType = originalType;
                return;
            }
            if (targetType == typeof(float))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.Emit(OpCodes.Conv_R4);
                context.CurrentType = originalType;
                return;
            }
            if (targetType == typeof(double))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.Emit(OpCodes.Conv_R8);
                context.CurrentType = originalType;
                return;
            }
            Func <MethodInfo, bool> coverterPredicate = method =>
            {
                if (method.Name == "op_Implicit")
                {
                    var parameters = method.GetParameters();
                    return(parameters.Length == 1 && parameters[0].ParameterType == typeof(int));
                }
                return(false);
            };
#if NetCore
            var reflectingType = targetType.GetTypeInfo();
            if (targetType == typeof(decimal))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.EmitCall(reflectingType.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(coverterPredicate));
                context.CurrentType = originalType;
                return;
            }
#else
            var reflectingType = targetType;
            if (targetType == typeof(decimal))
            {
                context.Emit(OpCodes.Ldc_I4_0);
                context.EmitCall(reflectingType.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(coverterPredicate));
                context.CurrentType = originalType;
                return;
            }
#endif
            var field = reflectingType.GetField("Empty", BindingFlags.Public | BindingFlags.Static) ??
                        reflectingType.GetField("Zero", BindingFlags.Public | BindingFlags.Static) ??
                        reflectingType.GetField("MinValue", BindingFlags.Public | BindingFlags.Static);
            if (field != null)
            {
                context.Emit(OpCodes.Ldsfld, field);
                context.CurrentType = field.FieldType;
                context.EmitCast(originalType);
                return;
            }
            var property = reflectingType.GetProperty("Empty", BindingFlags.Public | BindingFlags.Static) ??
                           reflectingType.GetProperty("Zero", BindingFlags.Public | BindingFlags.Static) ??
                           reflectingType.GetProperty("MinValue", BindingFlags.Public | BindingFlags.Static);
            var getMethod = property?.GetGetMethod();
            if (getMethod != null)
            {
                context.EmitCall(getMethod);
                context.CurrentType = getMethod.ReturnType;
                context.EmitCast(originalType);
                return;
            }
            var targetLocal = context.DeclareLocal(targetType);
            context.Emit(OpCodes.Ldloca, targetLocal);
            context.Emit(OpCodes.Initobj, targetType);
            context.Emit(OpCodes.Ldloc, targetLocal);
            context.CurrentType = originalType;
        }
예제 #10
0
        public override void Emit(Type sourceType, Type targetType, CompilationContext context)
        {
#if NETSTANDARD
            var reflectingTargetType = targetType.GetTypeInfo();
#else
            var reflectingTargetType = targetType;
#endif
            context.EmitCast(typeof(IEnumerable <>).MakeGenericType(_sourceElementType));
            _invokerBuilder.Emit(context);
            if (reflectingTargetType.IsGenericType)
            {
                var genericTypeDefinition = targetType.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof(IList <>) || genericTypeDefinition == typeof(ICollection <>) || genericTypeDefinition == typeof(IEnumerable <>))
                {
                    context.EmitCast(targetType);
                    context.CurrentType = targetType;
                    return;
                }
            }
            else if (targetType.IsArray)
            {
                context.EmitCast(targetType);
                context.CurrentType = targetType;
                return;
            }

            var labelNull     = context.DefineLabel();
            var labelComplete = context.DefineLabel();
            var local         = context.DeclareLocal(context.CurrentType);
            context.Emit(OpCodes.Stloc, local);

            context.Emit(OpCodes.Ldloc, local);
            context.Emit(OpCodes.Brfalse, labelNull);
            context.Emit(OpCodes.Ldloc, local);

            if (targetType.IsEnumerable(out var targetElementType))
            {
                var constructor = reflectingTargetType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { typeof(IList <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { typeof(ICollection <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { targetElementType.MakeArrayType() });
                if (constructor != null)
                {
                    context.EmitCast(constructor.GetParameters()[0].ParameterType);
                    context.Emit(OpCodes.Newobj, constructor);
                }
                else
                {
                    var defaultConstructor = reflectingTargetType.GetConstructor(Type.EmptyTypes);
                    var addMethod          = reflectingTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(method =>
                    {
                        if (method.Name != "Add")
                        {
                            return(false);
                        }
                        var parameters = method.GetParameters();
                        return(parameters.Length == 1 && parameters[0].ParameterType == targetElementType);
                    }).FirstOrDefault();
                    if (defaultConstructor != null && addMethod != null)
                    {
                        var targetArrayType = targetElementType.MakeArrayType();
                        var targetArray     = context.DeclareLocal(targetArrayType);
                        var targetInstance  = context.DeclareLocal(targetType);
                        var index           = context.DeclareLocal(typeof(int));

                        context.EmitCast(targetArrayType);
                        context.Emit(OpCodes.Stloc, targetArray);

                        context.Emit(OpCodes.Newobj, defaultConstructor);
                        context.Emit(OpCodes.Stloc, targetInstance);

                        // var i = 0;
                        context.Emit(OpCodes.Ldc_I4_0);
                        context.Emit(OpCodes.Stloc, index);

                        var labelEnd = context.DefineLabel();
                        context.Emit(OpCodes.Br_S, labelEnd);
                        var labelStart = context.DefineLabel();
                        context.MakeLabel(labelStart);

                        // target.Add(array[i]);
                        context.Emit(OpCodes.Ldloc, targetInstance);
                        context.Emit(OpCodes.Ldloc, targetArray);
                        context.Emit(OpCodes.Ldloc, index);
#if NETSTANDARD
                        var targetElementTypeInfo = targetElementType.GetTypeInfo();
                        if (targetElementTypeInfo.IsValueType && !targetElementTypeInfo.IsPrimitive)
#else
                        if (targetElementType.IsValueType && !targetElementType.IsPrimitive)
#endif
                        {
                            context.Emit(OpCodes.Ldelema, targetElementType);
                        }
                        else
                        {
                            context.Emit(OpCodes.Ldelem, targetElementType);
                        }
                        context.EmitCall(addMethod);

                        // i++
                        context.Emit(OpCodes.Ldloc, index);
                        context.Emit(OpCodes.Ldc_I4_1);
                        context.Emit(OpCodes.Add);
                        context.Emit(OpCodes.Stloc, index);


                        context.MakeLabel(labelEnd);
                        context.Emit(OpCodes.Ldloc, index);
                        context.Emit(OpCodes.Ldloc, targetArray);
                        context.Emit(OpCodes.Ldlen);
                        context.Emit(OpCodes.Conv_I4);
                        context.Emit(OpCodes.Blt_S, labelStart);

                        context.Emit(OpCodes.Ldloc, targetInstance);
                    }
                }
            }

            context.Emit(OpCodes.Br_S, labelComplete);
            context.MakeLabel(labelNull);
            context.Emit(OpCodes.Ldnull);
            context.MakeLabel(labelComplete);
            context.CurrentType = targetType;
        }
예제 #11
0
 internal override void EmitGetter(CompilationContext context)
 {
     context.LoadSource(LoadPurpose.MemberAccess);
     context.Emit(OpCodes.Ldfld, _field);
     context.CurrentType = _field.FieldType;
 }