private static void EmitNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked, ILocalCache locals) { Debug.Assert(typeFrom.IsNullableType()); Debug.Assert(typeTo.IsNullableType()); Label labIfNull; Label labEnd; LocalBuilder locFrom = locals.GetLocal(typeFrom); il.Emit(OpCodes.Stloc, locFrom); LocalBuilder locTo = locals.GetLocal(typeTo); // test for null il.Emit(OpCodes.Ldloca, locFrom); il.EmitHasValue(typeFrom); labIfNull = il.DefineLabel(); il.Emit(OpCodes.Brfalse_S, labIfNull); il.Emit(OpCodes.Ldloca, locFrom); locals.FreeLocal(locFrom); il.EmitGetValueOrDefault(typeFrom); Type nnTypeFrom = typeFrom.GetNonNullableType(); Type nnTypeTo = typeTo.GetNonNullableType(); il.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked, locals); // construct result type ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo }); il.Emit(OpCodes.Newobj, ci); il.Emit(OpCodes.Stloc, locTo); labEnd = il.DefineLabel(); il.Emit(OpCodes.Br_S, labEnd); // if null then create a default one il.MarkLabel(labIfNull); il.Emit(OpCodes.Ldloca, locTo); il.Emit(OpCodes.Initobj, typeTo); il.MarkLabel(labEnd); il.Emit(OpCodes.Ldloc, locTo); locals.FreeLocal(locTo); }
private static void EmitNullableToNonNullableStructConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked, ILocalCache locals) { Debug.Assert(typeFrom.IsNullableType()); Debug.Assert(!typeTo.IsNullableType()); Debug.Assert(typeTo.GetTypeInfo().IsValueType); LocalBuilder locFrom = locals.GetLocal(typeFrom); il.Emit(OpCodes.Stloc, locFrom); il.Emit(OpCodes.Ldloca, locFrom); locals.FreeLocal(locFrom); il.EmitGetValue(typeFrom); Type nnTypeFrom = typeFrom.GetNonNullableType(); il.EmitConvertToType(nnTypeFrom, typeTo, isChecked, locals); }
private static void EmitNonNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked, ILocalCache locals) { Debug.Assert(!typeFrom.IsNullableType()); Debug.Assert(typeTo.IsNullableType()); LocalBuilder locTo = locals.GetLocal(typeTo); Type nnTypeTo = typeTo.GetNonNullableType(); il.EmitConvertToType(typeFrom, nnTypeTo, isChecked, locals); ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo }); il.Emit(OpCodes.Newobj, ci); il.Emit(OpCodes.Stloc, locTo); il.Emit(OpCodes.Ldloc, locTo); locals.FreeLocal(locTo); }
/// <summary> /// Emits default(T) /// Semantics match C# compiler behavior /// </summary> internal static void EmitDefault(this ILGenerator il, Type type, ILocalCache locals) { switch (type.GetTypeCode()) { case TypeCode.DateTime: il.Emit(OpCodes.Ldsfld, DateTime_MinValue); break; case TypeCode.Object: if (type.GetTypeInfo().IsValueType) { // Type.GetTypeCode on an enum returns the underlying // integer TypeCode, so we won't get here. Debug.Assert(!type.GetTypeInfo().IsEnum); // This is the IL for default(T) if T is a generic type // parameter, so it should work for any type. It's also // the standard pattern for structs. LocalBuilder lb = locals.GetLocal(type); il.Emit(OpCodes.Ldloca, lb); il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Ldloc, lb); locals.FreeLocal(lb); break; } goto case TypeCode.Empty; case TypeCode.Empty: case TypeCode.String: case TypeCode.DBNull: il.Emit(OpCodes.Ldnull); break; case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: il.Emit(OpCodes.Ldc_I4_0); break; case TypeCode.Int64: case TypeCode.UInt64: il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I8); break; case TypeCode.Single: il.Emit(OpCodes.Ldc_R4, default(float)); break; case TypeCode.Double: il.Emit(OpCodes.Ldc_R8, default(double)); break; case TypeCode.Decimal: il.Emit(OpCodes.Ldsfld, Decimal_Zero); break; default: throw ContractUtils.Unreachable; } }