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 nnExprType = typeFrom.Unwrap(); var nnType = typeTo.Unwrap(); if (nnType == nnExprType || nnType.IsEquivalentTo(nnExprType)) { return; } if (typeFrom.IsInterface || // interface cast typeTo.IsInterface || typeFrom == typeof(object) || // boxing cast typeTo == typeof(object) || typeFrom == typeof(Enum) || typeFrom == typeof(ValueType) || TypeInfoUtils.IsLegalExplicitVariantDelegateConversion(typeFrom, typeTo)) { ilGenerator.EmitCastToType(typeFrom, typeTo); } else if (typeFrom.IsNullableType() || typeTo.IsNullableType()) { ilGenerator.EmitNullableConversion(typeFrom, typeTo, isChecked); } else if (!(typeFrom.IsConvertible() && typeTo.IsConvertible()) // primitive runtime conversion && (nnExprType.GetTypeInfo().IsAssignableFrom(nnType) || // down cast nnType.GetTypeInfo().IsAssignableFrom(nnExprType))) // up cast { ilGenerator.EmitCastToType(typeFrom, typeTo); } else if (typeFrom.IsArray && typeTo.IsArray) { // See DevDiv Bugs #94657. ilGenerator.EmitCastToType(typeFrom, typeTo); } else { ilGenerator.EmitNumericConversion(typeFrom, typeTo, 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); }
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).GetTypeInfo(); var nnDestType = TypeInfoUtils.GetNonNullableType(dest).GetTypeInfo(); // 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) { var isFromUnsigned = TypeInfoUtils.IsUnsigned(typeFrom); var isFromFloatingPoint = TypeInfoUtils.IsFloatingPoint(typeFrom); if (typeTo == typeof(float)) { 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 = typeTo.GetTypeCode(); 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(); } } } }