private static void EmitNullableToNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked)
        {
            Label        labIfNull = default(Label);
            Label        labEnd    = default(Label);
            LocalBuilder locFrom   = null;
            LocalBuilder locTo     = null;

            locFrom = ilGenerator.DeclareLocal(typeFrom);
            ilGenerator.Emit(OpCodes.Stloc, locFrom);
            locTo = ilGenerator.DeclareLocal(typeTo);
            // test for null
            ilGenerator.Emit(OpCodes.Ldloca, locFrom);
            ilGenerator.EmitHasValue(typeFrom);
            labIfNull = ilGenerator.DefineLabel();
            ilGenerator.Emit(OpCodes.Brfalse_S, labIfNull);
            ilGenerator.Emit(OpCodes.Ldloca, locFrom);
            ilGenerator.EmitGetValueOrDefault(typeFrom);
            Type nnTypeFrom = TypeInfoUtils.GetNonNullableType(typeFrom);
            Type nnTypeTo   = TypeInfoUtils.GetNonNullableType(typeTo);

            ilGenerator.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked);
            // construct result type
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });

            ilGenerator.Emit(OpCodes.Newobj, ci);
            ilGenerator.Emit(OpCodes.Stloc, locTo);
            labEnd = ilGenerator.DefineLabel();
            ilGenerator.Emit(OpCodes.Br_S, labEnd);
            // if null then create a default one
            ilGenerator.MarkLabel(labIfNull);
            ilGenerator.Emit(OpCodes.Ldloca, locTo);
            ilGenerator.Emit(OpCodes.Initobj, typeTo);
            ilGenerator.MarkLabel(labEnd);
            ilGenerator.Emit(OpCodes.Ldloc, locTo);
        }
        public static void EmitConvertToType(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked = true)
        {
            if (ilGenerator == null)
            {
                throw new ArgumentNullException(nameof(ilGenerator));
            }
            if (typeFrom == null)
            {
                throw new ArgumentNullException(nameof(typeFrom));
            }
            if (typeTo == null)
            {
                throw new ArgumentNullException(nameof(typeTo));
            }

            var typeFromInfo = typeFrom;
            var typeToInfo   = typeTo;

            var nnExprType = typeFromInfo.GetNonNullableType();
            var nnType     = typeToInfo.GetNonNullableType();

            if (TypeInfoUtils.AreEquivalent(typeFromInfo, typeToInfo))
            {
                return;
            }

            if (typeFromInfo.IsInterface ||   // interface cast
                typeToInfo.IsInterface ||
                typeFrom == typeof(object) || // boxing cast
                typeTo == typeof(object) ||
                typeFrom == typeof(System.Enum) ||
                typeFrom == typeof(System.ValueType) ||
                TypeInfoUtils.IsLegalExplicitVariantDelegateConversion(typeFromInfo, typeToInfo))
            {
                ilGenerator.EmitCastToType(typeFromInfo, typeToInfo);
            }
            else if (typeFromInfo.IsNullableType() || typeToInfo.IsNullableType())
            {
                ilGenerator.EmitNullableConversion(typeFromInfo, typeToInfo, isChecked);
            }
            else if (!(typeFromInfo.IsConvertible() && typeToInfo.IsConvertible()) // primitive runtime conversion
                     &&
                     (nnExprType.IsAssignableFrom(nnType) ||                       // down cast
                      nnType.IsAssignableFrom(nnExprType)))                        // up cast
            {
                ilGenerator.EmitCastToType(typeFromInfo, typeToInfo);
            }
            else if (typeFromInfo.IsArray && typeToInfo.IsArray)
            {
                // See DevDiv Bugs #94657.
                ilGenerator.EmitCastToType(typeFromInfo, typeToInfo);
            }
            else
            {
                ilGenerator.EmitNumericConversion(typeFromInfo, typeToInfo, isChecked);
            }
        }
        private static void EmitNullableToNonNullableStructConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked)
        {
            LocalBuilder locFrom = null;

            locFrom = ilGenerator.DeclareLocal(typeFrom);
            ilGenerator.Emit(OpCodes.Stloc, locFrom);
            ilGenerator.Emit(OpCodes.Ldloca, locFrom);
            ilGenerator.EmitGetValue(typeFrom);
            Type nnTypeFrom = TypeInfoUtils.GetNonNullableType(typeFrom);

            ilGenerator.EmitConvertToType(nnTypeFrom, typeTo, isChecked);
        }
        private static void EmitNonNullableToNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked)
        {
            LocalBuilder locTo = null;

            locTo = ilGenerator.DeclareLocal(typeTo);
            Type nnTypeTo = TypeInfoUtils.GetNonNullableType(typeTo);

            ilGenerator.EmitConvertToType(typeFrom, nnTypeTo, isChecked);
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });

            ilGenerator.Emit(OpCodes.Newobj, ci);
            ilGenerator.Emit(OpCodes.Stloc, locTo);
            ilGenerator.Emit(OpCodes.Ldloc, locTo);
        }
        private static void EmitNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked)
        {
            bool isTypeFromNullable = TypeInfoUtils.IsNullableType(typeFrom);
            bool isTypeToNullable   = TypeInfoUtils.IsNullableType(typeTo);

            if (isTypeFromNullable && isTypeToNullable)
            {
                ilGenerator.EmitNullableToNullableConversion(typeFrom, typeTo, isChecked);
            }
            else if (isTypeFromNullable)
            {
                ilGenerator.EmitNullableToNonNullableConversion(typeFrom, typeTo, isChecked);
            }
            else
            {
                ilGenerator.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked);
            }
        }
Пример #6
0
        internal static bool HasReferenceConversion(Type source, Type dest)
        {
            // void -> void conversion is handled elsewhere
            // (it's an identity conversion)
            // All other void conversions are disallowed.
            if (source == typeof(void) || dest == typeof(void))
            {
                return(false);
            }

            var nnSourceType = TypeInfoUtils.GetNonNullableType(source);
            var nnDestType   = TypeInfoUtils.GetNonNullableType(dest);

            // Down conversion
            if (nnSourceType.IsAssignableFrom(nnDestType))
            {
                return(true);
            }
            // Up conversion
            if (nnDestType.IsAssignableFrom(nnSourceType))
            {
                return(true);
            }
            // Interface conversion
            if (source.IsInterface || dest.IsInterface)
            {
                return(true);
            }
            // Variant delegate conversion
            if (IsLegalExplicitVariantDelegateConversion(source, dest))
            {
                return(true);
            }

            // Object conversion
            if (source == typeof(object) || dest == typeof(object))
            {
                return(true);
            }
            return(false);
        }
        private static void EmitNumericConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked)
        {
            bool isFromUnsigned      = TypeInfoUtils.IsUnsigned(typeFrom);
            bool isFromFloatingPoint = TypeInfoUtils.IsFloatingPoint(typeFrom);

            if (typeTo == typeof(Single))
            {
                if (isFromUnsigned)
                {
                    ilGenerator.Emit(OpCodes.Conv_R_Un);
                }
                ilGenerator.Emit(OpCodes.Conv_R4);
            }
            else if (typeTo == typeof(Double))
            {
                if (isFromUnsigned)
                {
                    ilGenerator.Emit(OpCodes.Conv_R_Un);
                }
                ilGenerator.Emit(OpCodes.Conv_R8);
            }
            else
            {
                TypeCode tc = Type.GetTypeCode(typeTo);
                if (isChecked)
                {
                    // Overflow checking needs to know if the source value on the IL stack is unsigned or not.
                    if (isFromUnsigned)
                    {
                        switch (tc)
                        {
                        case TypeCode.SByte:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I1_Un);
                            break;

                        case TypeCode.Int16:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I2_Un);
                            break;

                        case TypeCode.Int32:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I4_Un);
                            break;

                        case TypeCode.Int64:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I8_Un);
                            break;

                        case TypeCode.Byte:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U1_Un);
                            break;

                        case TypeCode.UInt16:
                        case TypeCode.Char:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U2_Un);
                            break;

                        case TypeCode.UInt32:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U4_Un);
                            break;

                        case TypeCode.UInt64:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U8_Un);
                            break;

                        default:
                            throw new InvalidCastException();
                        }
                    }
                    else
                    {
                        switch (tc)
                        {
                        case TypeCode.SByte:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I1);
                            break;

                        case TypeCode.Int16:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I2);
                            break;

                        case TypeCode.Int32:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I4);
                            break;

                        case TypeCode.Int64:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_I8);
                            break;

                        case TypeCode.Byte:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U1);
                            break;

                        case TypeCode.UInt16:
                        case TypeCode.Char:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U2);
                            break;

                        case TypeCode.UInt32:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U4);
                            break;

                        case TypeCode.UInt64:
                            ilGenerator.Emit(OpCodes.Conv_Ovf_U8);
                            break;

                        default:
                            throw new InvalidCastException();
                        }
                    }
                }
                else
                {
                    switch (tc)
                    {
                    case TypeCode.SByte:
                        ilGenerator.Emit(OpCodes.Conv_I1);
                        break;

                    case TypeCode.Byte:
                        ilGenerator.Emit(OpCodes.Conv_U1);
                        break;

                    case TypeCode.Int16:
                        ilGenerator.Emit(OpCodes.Conv_I2);
                        break;

                    case TypeCode.UInt16:
                    case TypeCode.Char:
                        ilGenerator.Emit(OpCodes.Conv_U2);
                        break;

                    case TypeCode.Int32:
                        ilGenerator.Emit(OpCodes.Conv_I4);
                        break;

                    case TypeCode.UInt32:
                        ilGenerator.Emit(OpCodes.Conv_U4);
                        break;

                    case TypeCode.Int64:
                        if (isFromUnsigned)
                        {
                            ilGenerator.Emit(OpCodes.Conv_U8);
                        }
                        else
                        {
                            ilGenerator.Emit(OpCodes.Conv_I8);
                        }
                        break;

                    case TypeCode.UInt64:
                        if (isFromUnsigned || isFromFloatingPoint)
                        {
                            ilGenerator.Emit(OpCodes.Conv_U8);
                        }
                        else
                        {
                            ilGenerator.Emit(OpCodes.Conv_I8);
                        }
                        break;

                    default:
                        throw new InvalidCastException();
                    }
                }
            }
        }