private static LocalBuilder[] EmitLoadParameters(DelegateBuildInfo info, ILGenerator il, int argumentArrayIndex) { if (!info.Method.IsStatic && !(info.Method is ConstructorInfo)) { il.Emit(OpCodes.Ldarg_0); EmitUnboxOrCast(il, info.Method.DeclaringType); } var locals = new LocalBuilder[info.RefParameterIndexes.Count]; var localIndex = 0; for (int index = 0; index < info.Parameters.Length; index++) { if (!info.Parameters[index].IsOut) { EmitLoadArg(il, argumentArrayIndex); EmitLoadInt(il, index); il.Emit(OpCodes.Ldelem_Ref); EmitUnboxOrCast(il, info.ParameterTypes[index]); if (info.Parameters[index].ParameterType.IsByRef) { locals[localIndex] = il.DeclareLocal(info.ParameterTypes[index], true); il.Emit(OpCodes.Stloc, locals[localIndex]); il.Emit(OpCodes.Ldloca_S, locals[localIndex++]); } } else { locals[localIndex] = il.DeclareLocal(info.ParameterTypes[index], true); il.Emit(OpCodes.Ldloca_S, locals[localIndex++]); } } return(locals); }
/// <summary> /// Creates a new <see cref="Invoker"/> that calls the specified method in a /// late-bound manner. /// </summary> /// <param name="method">The method that the invoker should call.</param> /// <returns>A dynamic invoker that can call the specified method.</returns> public static Invoker CreateInvoker(MethodInfo method) { DynamicMethod callable = CreateDynamicInvoker(); var info = new DelegateBuildInfo(method); ILGenerator il = callable.GetILGenerator(); EmitCheckParameters(info, il, 1); var locals = EmitLoadParameters(info, il, 1); il.EmitCall(method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, method, null); if (method.ReturnType == typeof(void)) { il.Emit(OpCodes.Ldnull); } else { if (info.ReturnType.IsValueType) { il.Emit(OpCodes.Box, method.ReturnType); } } EmitReturnRefValues(info, il, locals); il.Emit(OpCodes.Ret); return callable.CreateDelegate(typeof(Invoker)) as Invoker; }
/*----------------------------------------------------------------------------------------*/ #region Public Methods /// <summary> /// Creates a new <see cref="Invoker"/> that calls the specified method in a /// late-bound manner. /// </summary> /// <param name="method">The method that the invoker should call.</param> /// <returns>A dynamic invoker that can call the specified method.</returns> public static Invoker CreateInvoker(MethodInfo method) { DynamicMethod callable = CreateDynamicInvoker(); var info = new DelegateBuildInfo(method); ILGenerator il = callable.GetILGenerator(); EmitCheckParameters(info, il, 1); EmitLoadParameters(info, il, 1); if (method.IsStatic) { il.EmitCall(OpCodes.Call, method, null); } else { il.EmitCall(OpCodes.Callvirt, method, null); } if (method.ReturnType == typeof(void)) { il.Emit(OpCodes.Ldnull); } else { if (info.ReturnType.IsValueType) { il.Emit(OpCodes.Box, method.ReturnType); } } il.Emit(OpCodes.Ret); return(callable.CreateDelegate(typeof(Invoker)) as Invoker); }
/*----------------------------------------------------------------------------------------*/ #region Private Methods: Utility private static void EmitCheckParameters(DelegateBuildInfo info, ILGenerator il, int argumentArrayIndex) { Label beginLabel = il.DefineLabel(); EmitLoadArg(il, argumentArrayIndex); il.Emit(OpCodes.Ldlen); EmitLoadInt(il, info.Parameters.Length); il.Emit(OpCodes.Beq, beginLabel); il.Emit(OpCodes.Newobj, TargetParameterCountExceptionConstructor); il.Emit(OpCodes.Throw); il.MarkLabel(beginLabel); }
private static void EmitReturnRefValues(DelegateBuildInfo info, ILGenerator il, LocalBuilder[] locals) { for (int i = 0; i < locals.Length; i++) { il.Emit(OpCodes.Ldarg_1); EmitLoadInt(il, info.RefParameterIndexes[i]); il.Emit(OpCodes.Ldloc, locals[i]); if (locals[i].LocalType.IsValueType) { il.Emit(OpCodes.Box, locals[i].LocalType); } il.Emit(OpCodes.Stelem_Ref); } }
/*----------------------------------------------------------------------------------------*/ private static void EmitLoadParameters(DelegateBuildInfo info, ILGenerator il, int argumentArrayIndex) { if (!info.Method.IsStatic && !(info.Method is ConstructorInfo)) { il.Emit(OpCodes.Ldarg_0); EmitUnboxOrCast(il, info.Method.DeclaringType); } for (int index = 0; index < info.Parameters.Length; index++) { EmitLoadArg(il, argumentArrayIndex); EmitLoadInt(il, index); il.Emit(OpCodes.Ldelem_Ref); EmitUnboxOrCast(il, info.ParameterTypes[index]); } }
/// <summary> /// Creates a new <see cref="FactoryMethod"/> that calls the specified constructor in a /// late-bound manner. /// </summary> /// <param name="constructor">The constructor that the factory method should call.</param> /// <returns>A dynamic factory method that can call the specified constructor.</returns> public static FactoryMethod CreateFactoryMethod(ConstructorInfo constructor) { DynamicMethod callable = CreateDynamicFactoryMethod(); var info = new DelegateBuildInfo(constructor); Type returnType = constructor.ReflectedType; ILGenerator il = callable.GetILGenerator(); EmitCheckParameters(info, il, 0); EmitLoadParameters(info, il, 0); il.Emit(OpCodes.Newobj, constructor); if (info.ReturnType.IsValueType) { il.Emit(OpCodes.Box, returnType); } il.Emit(OpCodes.Ret); return(callable.CreateDelegate(typeof(FactoryMethod)) as FactoryMethod); }
/// <summary> /// Creates a new <see cref="FactoryMethod"/> that calls the specified constructor in a /// late-bound manner. /// </summary> /// <param name="constructor">The constructor that the factory method should call.</param> /// <returns>A dynamic factory method that can call the specified constructor.</returns> public static FactoryMethod CreateFactoryMethod(ConstructorInfo constructor) { DynamicMethod callable = CreateDynamicFactoryMethod(); var info = new DelegateBuildInfo(constructor); Type returnType = constructor.ReflectedType; ILGenerator il = callable.GetILGenerator(); EmitCheckParameters(info, il, 0); EmitLoadParameters(info, il, 0); il.Emit(OpCodes.Newobj, constructor); if (info.ReturnType.IsValueType) { il.Emit(OpCodes.Box, returnType); } il.Emit(OpCodes.Ret); return callable.CreateDelegate(typeof(FactoryMethod)) as FactoryMethod; }
private static LocalBuilder[] EmitLoadParameters(DelegateBuildInfo info, ILGenerator il, int argumentArrayIndex) { if (!info.Method.IsStatic && !(info.Method is ConstructorInfo)) { il.Emit(OpCodes.Ldarg_0); EmitUnboxOrCast(il, info.Method.DeclaringType); } var locals = new LocalBuilder[info.RefParameterIndexes.Count]; var localIndex = 0; for (int index = 0; index < info.Parameters.Length; index++) { EmitLoadArg(il, argumentArrayIndex); EmitLoadInt(il, index); il.Emit(OpCodes.Ldelem_Ref); EmitUnboxOrCast(il, info.ParameterTypes[index]); if (info.Parameters[index].ParameterType.IsByRef) { locals[localIndex] = il.DeclareLocal(info.ParameterTypes[index], true); il.Emit(OpCodes.Stloc, locals[localIndex]); il.Emit(OpCodes.Ldloca_S, locals[localIndex++]); } } return locals; }
private static void EmitCheckParameters(DelegateBuildInfo info, ILGenerator il, int argumentArrayIndex) { Label beginLabel = il.DefineLabel(); EmitLoadArg(il, argumentArrayIndex); il.Emit(OpCodes.Ldlen); EmitLoadInt(il, info.Parameters.Length); il.Emit(OpCodes.Beq, beginLabel); il.Emit(OpCodes.Newobj, TargetParameterCountExceptionConstructor); il.Emit(OpCodes.Throw); il.MarkLabel(beginLabel); }