private bool EmitNullableSource(CompilationContext context, Type sourceType, Type targetType)
        {
#if NETSTANDARD
            var reflectingSourceType = sourceType.GetTypeInfo();
#else
            var reflectingSourceType = sourceType;
#endif
            var sourceUnderlingType = reflectingSourceType.GetGenericArguments()[0];
            var converter           = GetConvertEmitter(sourceUnderlingType, targetType);
            if (converter != null)
            {
                var target = context.DeclareLocal(targetType);
                var local  = context.DeclareLocal(sourceType);
                context.Emit(OpCodes.Stloc, local);

                context.EmitNullableExpression(local, ctx =>
                {
                    converter(ctx);
                    ctx.Emit(OpCodes.Stloc, target);
                }, ctx =>
                {
                    context.EmitDefault(targetType);
                    context.Emit(OpCodes.Stloc, target);
                });
                context.Emit(OpCodes.Ldloc, target);
                return(true);
            }
            return(false);
        }
Beispiel #2
0
        public override void Emit(Type sourceType, Type targetType, CompilationContext context)
        {
            if (sourceType == typeof(string))
            {
                return;
            }
            if (sourceType.IsNullable())
            {
                var target = context.DeclareLocal(targetType);
                var local  = context.DeclareLocal(sourceType);
                context.Emit(OpCodes.Stloc, local);
                context.EmitNullableExpression(local, ctx =>
                {
                    ctx.EmitCast(typeof(object));
                    ctx.EmitCall(_toStringMethod);
                    ctx.Emit(OpCodes.Stloc, target);
                }, ctx =>
                {
                    ctx.EmitDefault(typeof(string));
                    ctx.Emit(OpCodes.Stloc, target);
                });
                context.Emit(OpCodes.Ldloc, target);
            }
#if NETSTANDARD
            else if (sourceType.GetTypeInfo().IsValueType)
#else
            else if (sourceType.IsValueType)
#endif
            {
                context.EmitCast(typeof(object));
                context.EmitCall(_toStringMethod);
            }
            else
            {
                var target = context.DeclareLocal(targetType);
                var local  = context.DeclareLocal(sourceType);
                context.Emit(OpCodes.Stloc, local);
                context.EmitNullableExpression(local, ctx =>
                {
                    ctx.EmitCast(typeof(object));
                    ctx.EmitCall(_toStringMethod);
                    ctx.Emit(OpCodes.Stloc, target);
                }, ctx =>
                {
                    context.Emit(OpCodes.Ldnull);
                    ctx.Emit(OpCodes.Stloc, target);
                });
                context.Emit(OpCodes.Ldloc, target);
            }

            context.CurrentType = targetType;
        }
Beispiel #3
0
        public void Emit(CompilationContext context)
        {
#if NETSTANDARD
            var reflectingTargetType = typeof(TTarget).GetTypeInfo();
#else
            var reflectingTargetType = typeof(TTarget);
#endif
            if (reflectingTargetType.IsValueType || typeof(TTarget).IsNullable())
            {
                var targetLocal = context.DeclareLocal(typeof(TTarget));
                context.Emit(OpCodes.Ldloca, targetLocal);
                context.Emit(OpCodes.Initobj, typeof(TTarget));
                context.Emit(OpCodes.Ldloc, targetLocal);
            }
            else
            {
                var constructor =
                    reflectingTargetType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
                    .FirstOrDefault(ctor => ctor.GetParameters().Length == 0);
                if (constructor == null)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Creator_CannotFindConstructor, typeof(TTarget)));
                }
                context.Emit(OpCodes.Newobj, constructor);
            }
            context.CurrentType = typeof(TTarget);
        }
        private bool EmitBothNullable(CompilationContext context, Type sourceType, Type targetType)
        {
#if NETSTANDARD
            var reflectingTargetType = targetType.GetTypeInfo();
            var reflectingSourceType = sourceType.GetTypeInfo();
#else
            var reflectingTargetType = targetType;
            var reflectingSourceType = sourceType;
#endif
            var sourceUnderlingType  = reflectingSourceType.GetGenericArguments()[0];
            var targetUnderlingyType = reflectingTargetType.GetGenericArguments()[0];
            // When the source and target member are the same nullbale type
            if (targetUnderlingyType == sourceUnderlingType)
            {
                return(true);
            }
            // When the source and target member are not the same nullable type,
            // But their underlying type can be implicitly or explicitly converted.
            var converter = GetConvertEmitter(sourceUnderlingType, targetUnderlingyType);
            if (converter != null)
            {
                var target = context.DeclareLocal(targetType);
                var local  = context.DeclareLocal(sourceType);
                context.Emit(OpCodes.Stloc, local);

                context.EmitNullableExpression(local, ctx =>
                {
                    converter(ctx);
                    ctx.Emit(OpCodes.Newobj, reflectingTargetType.GetConstructors()[0]);
                    ctx.Emit(OpCodes.Stloc, target);
                }, ctx =>
                {
                    ctx.EmitDefault(targetType);
                    ctx.Emit(OpCodes.Stloc, target);
                });
                context.Emit(OpCodes.Ldloc, target);
                return(true);
            }
            return(false);
        }
Beispiel #5
0
        internal override void EmitSetter(CompilationContext context)
        {
            var local = context.DeclareLocal(context.CurrentType);

            context.Emit(OpCodes.Stloc, local);
            context.LoadTarget(LoadPurpose.MemberAccess);
            context.Emit(OpCodes.Ldloc, local);
            if (MemberType != context.CurrentType)
            {
                context.EmitCast(MemberType);
            }
            context.Emit(OpCodes.Stfld, _field);
            context.CurrentType = null;
        }
Beispiel #6
0
 public void Emit(CompilationContext context)
 {
     if (_invokeMethod != null)
     {
         context.EmitCall(_invokeMethod);
     }
     else if (TypeMapper <TSource, TTarget> .TryGetInstance(_container, out var mapper))
     {
         var sourceLocal = context.DeclareLocal(typeof(IEnumerable <TSource>));
         context.EmitCast(typeof(IEnumerable <TSource>));
         context.ILGenerator.Emit(OpCodes.Stloc, sourceLocal);
         EmitConverter(context.ILGenerator, mapper.ConverterMethod,
                       () => context.ILGenerator.Emit(OpCodes.Ldloc, sourceLocal));
     }
     context.CurrentType = typeof(IEnumerable <TTarget>);
 }
Beispiel #7
0
        internal override void EmitSetter(CompilationContext context)
        {
            var local = context.DeclareLocal(context.CurrentType);

            context.Emit(OpCodes.Stloc, local);

            var setMethod = _property.GetSetMethod(true);

            context.LoadTarget(LoadPurpose.MemberAccess);
            context.Emit(OpCodes.Ldloc, local);
            if (MemberType != context.CurrentType)
            {
                context.EmitCast(MemberType);
            }
            context.EmitCall(setMethod);
            context.CurrentType = null;
        }
Beispiel #8
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);
            }
        }
        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;
        }
Beispiel #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;
        }