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); }
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); } }
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; }