示例#1
0
        public static void EmitCast(this CompilationContext context, Type targetType)
        {
            if (context.CurrentType == targetType)
            {
                return;
            }
            var currentTypeIsValue = context.CurrentType.GetTypeInfo().IsValueType;
            var targetTypeIsValue  = targetType.GetTypeInfo().IsValueType;

            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, "Cannot cast from type '{0}' to type '{1}'.", context.CurrentType, targetType));
                }
                else if (targetType != typeof(object))
                {
                    context.Emit(OpCodes.Castclass, targetType);
                }
            }
            context.CurrentType = targetType;
        }
示例#2
0
 public static void EmitCall(this CompilationContext context, MethodInfo method)
 {
     context.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method);
     context.CurrentType = method.ReturnType;
 }
示例#3
0
 public static void EmitTypeOf(this CompilationContext context, Type targetType)
 {
     context.Emit(OpCodes.Ldtoken, targetType);
     context.Emit(OpCodes.Call, _getTypeFromHandleMethod);
 }
示例#4
0
        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 (!targetType.GetTypeInfo().IsValueType)
            {
                context.Emit(OpCodes.Ldnull);
                context.CurrentType = originalType;
                return;
            }
            if (targetType.GetTypeInfo().IsEnum)
            {
                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);
            };
            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;
            }
            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;
        }