public static void EmitNullableExpression(this CompilationContext context, LocalBuilder local,
                                                  Action <CompilationContext> nonNullExpression, Action <CompilationContext> nullExpression)
        {
            var label = context.DefineLabel();

            if (local.LocalType.IsNullable())
            {
#if NetCore
                var variableType = local.LocalType.GetTypeInfo();
#else
                var variableType = local.LocalType;
#endif
                context.Emit(OpCodes.Ldloca, local);
                context.EmitCall(variableType.GetProperty("HasValue").GetGetMethod());
                context.Emit(OpCodes.Brfalse, label);

                context.Emit(OpCodes.Ldloca, local);
                context.EmitCall(variableType.GetProperty("Value").GetGetMethod());
                context.CurrentType = variableType.GetGenericArguments()[0];
            }
            else
            {
                context.Emit(OpCodes.Ldloc, local);
                context.Emit(OpCodes.Ldnull);
                context.EmitCall(_referenceEqualsMethod);
                context.Emit(OpCodes.Brtrue, label);

                context.Emit(OpCodes.Ldloc, local);
                context.CurrentType = local.LocalType;
            }
            nonNullExpression(context);

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

            context.MakeLabel(label);
            nullExpression(context);

            context.MakeLabel(labelEnd);
        }
Esempio n. 2
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);
            }
        }
Esempio n. 3
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;
        }