public virtual Delegate CreateDelegate(Type sourceType, Type targetType, ModuleBuilder builder) { var typeBuilder = builder.DefineStaticType(); var methodBuilder = typeBuilder.DefineStaticMethod("Map"); methodBuilder.SetParameters(sourceType, targetType); var il = methodBuilder.GetILGenerator(); var context = new CompilationContext(il); context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0)); context.SetTarget(purpose => il.Emit(OpCodes.Ldarg_1)); Emit(sourceType, targetType, context); context.Emit(OpCodes.Ret); #if NetCore return(typeBuilder.CreateTypeInfo() .GetMethod("Map", BindingFlags.Static | BindingFlags.Public) .CreateDelegate(typeof(Action <,>).MakeGenericType(sourceType, targetType))); #else return(Delegate.CreateDelegate(typeof(Action <,>).MakeGenericType(sourceType, targetType), typeBuilder.CreateType(), "Map")); #endif }
public virtual Delegate CreateDelegate(Type sourceType, Type targetType, ModuleBuilder builder) { var typeBuilder = builder.DefineStaticType(); var methodBuilder = typeBuilder.DefineStaticMethod("Convert"); methodBuilder.SetReturnType(targetType); methodBuilder.SetParameters(sourceType); var il = methodBuilder.GetILGenerator(); var context = new CompilationContext(il); il.Emit(OpCodes.Ldarg_0); context.CurrentType = sourceType; Emit(sourceType, targetType, context); context.Emit(OpCodes.Ret); #if NETSTANDARD return(typeBuilder.CreateTypeInfo() .GetMethod("Convert", BindingFlags.Static | BindingFlags.Public) .CreateDelegate(typeof(Func <,>).MakeGenericType(sourceType, targetType))); #else return(Delegate.CreateDelegate(typeof(Func <,>).MakeGenericType(sourceType, targetType), typeBuilder.CreateType(), "Convert")); #endif }
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 Action <TSource, TTarget> CreateMapper(ModuleBuilder builder) { Initialize(); if (_customMapper != null) { return(_customMapper); } var typeBuilder = builder.DefineStaticType(); var methodBuilder = typeBuilder.DefineStaticMethod("Map"); methodBuilder.SetReturnType(typeof(void)); methodBuilder.SetParameters(typeof(TSource), typeof(TTarget)); #if NetCore var reflectingTargetType = typeof(TTarget).GetTypeInfo(); var reflectingSourceType = typeof(TSource).GetTypeInfo(); #else var reflectingTargetType = typeof(TTarget); var reflectingSourceType = typeof(TSource); #endif var il = methodBuilder.GetILGenerator(); var context = new CompilationContext(il); if (reflectingSourceType.IsValueType) { context.SetSource(purpose => { if (purpose == LoadPurpose.MemberAccess) { il.Emit(OpCodes.Ldarga_S, 0); } else { il.Emit(OpCodes.Ldarg_0); } }); } else { context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0)); } if (reflectingTargetType.IsValueType) { context.SetTarget(purpose => { if (purpose == LoadPurpose.MemberAccess) { il.Emit(OpCodes.Ldarga_S, 1); } else { il.Emit(OpCodes.Ldarg_1); } }); } else { context.SetTarget(purpose => il.Emit(OpCodes.Ldarg_1)); } EmitMap(context); context.Emit(OpCodes.Ret); #if NetCore return((Action <TSource, TTarget>)typeBuilder.CreateTypeInfo().GetMethod("Map", BindingFlags.Static | BindingFlags.Public).CreateDelegate(typeof(Action <TSource, TTarget>))); #else return((Action <TSource, TTarget>)Delegate.CreateDelegate(typeof(Action <TSource, TTarget>), typeBuilder.CreateType(), "Map")); #endif }
public Func <TSource, TTarget> CreateConverter(ModuleBuilder builder) { Initialize(); var typeBuilder = builder.DefineStaticType(); var methodBuilder = typeBuilder.DefineStaticMethod("Convert"); methodBuilder.SetReturnType(typeof(TTarget)); methodBuilder.SetParameters(typeof(TSource)); ConverterMethod = methodBuilder; #if NETSTANDARD var reflectingTargetType = typeof(TTarget).GetTypeInfo(); var reflectingSourceType = typeof(TSource).GetTypeInfo(); #else var reflectingTargetType = typeof(TTarget); var reflectingSourceType = typeof(TSource); #endif var il = methodBuilder.GetILGenerator(); var context = new CompilationContext(il); if (reflectingSourceType.IsValueType) { context.SetSource(purpose => { if (purpose == LoadPurpose.MemberAccess) { il.Emit(OpCodes.Ldarga_S, 0); } else { il.Emit(OpCodes.Ldarg_0); } }); } else { context.SetSource(purpose => il.Emit(OpCodes.Ldarg_0)); } var targetLocal = il.DeclareLocal(typeof(TTarget)); _creator.Emit(context); il.Emit(OpCodes.Stloc, targetLocal); if (reflectingTargetType.IsValueType) { context.SetTarget( purpose => il.Emit(purpose == LoadPurpose.MemberAccess ? OpCodes.Ldloca_S : OpCodes.Ldloc, targetLocal)); } else { context.SetTarget(purpose => il.Emit(OpCodes.Ldloc, targetLocal)); } EmitMap(context); context.LoadTarget(LoadPurpose.ReturnValue); context.Emit(OpCodes.Ret); #if NETSTANDARD ConverterMethod = typeBuilder.CreateTypeInfo().GetMethod("Convert", BindingFlags.Static | BindingFlags.Public); return((Func <TSource, TTarget>)ConverterMethod.CreateDelegate(typeof(Func <TSource, TTarget>))); #else ConverterMethod = typeBuilder.CreateType().GetMethod("Convert", BindingFlags.Static | BindingFlags.Public); return((Func <TSource, TTarget>)Delegate.CreateDelegate(typeof(Func <TSource, TTarget>), ConverterMethod)); #endif }
public static void EmitCast(this CompilationContext context, Type targetType) { if (context.CurrentType == targetType) { return; } #if NetCore var currentTypeIsValue = context.CurrentType.GetTypeInfo().IsValueType; var targetTypeIsValue = targetType.GetTypeInfo().IsValueType; #else var currentTypeIsValue = context.CurrentType.IsValueType; var targetTypeIsValue = targetType.IsValueType; #endif 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, Strings.Emit_InvalidCastType, context.CurrentType, targetType)); } else if (targetType != typeof(object)) { context.Emit(OpCodes.Castclass, targetType); } } context.CurrentType = targetType; }
public static void EmitTypeOf(this CompilationContext context, Type targetType) { context.Emit(OpCodes.Ldtoken, targetType); context.Emit(OpCodes.Call, _getTypeFromHandleMethod); }
public static void EmitCall(this CompilationContext context, MethodInfo method) { context.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method); context.CurrentType = method.ReturnType; }
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 NetCore if (!targetType.GetTypeInfo().IsValueType) #else if (!targetType.IsValueType) #endif { context.Emit(OpCodes.Ldnull); context.CurrentType = originalType; return; } #if NetCore if (targetType.GetTypeInfo().IsEnum) #else if (targetType.IsEnum) #endif { 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); }; #if NetCore 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; } #else var reflectingType = targetType; if (targetType == typeof(decimal)) { context.Emit(OpCodes.Ldc_I4_0); context.EmitCall(reflectingType.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(coverterPredicate)); context.CurrentType = originalType; return; } #endif 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; }
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; }
internal override void EmitGetter(CompilationContext context) { context.LoadSource(LoadPurpose.MemberAccess); context.Emit(OpCodes.Ldfld, _field); context.CurrentType = _field.FieldType; }