/// <summary> /// This method generates the new method on runtime and passes a delegate to it. /// The actual generation is a *slow process*, so make sure to save the delegate /// for later usage, instead of generating each time. /// </summary> /// <param name="methodInfo"></param> /// <returns></returns> public static FastInvokeHandlerDelegate GetMethodInvoker(MethodInfo methodInfo, bool skipVisibility) { DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module, skipVisibility); ILGenerator il = dynamicMethod.GetILGenerator(); ParameterInfo[] ps = methodInfo.GetParameters(); Type[] paramTypes = new Type[ps.Length]; for (int i = 0; i < paramTypes.Length; i++) { if (ps[i].ParameterType.IsByRef) { paramTypes[i] = ps[i].ParameterType.GetElementType(); } else { paramTypes[i] = ps[i].ParameterType; } } LocalBuilder[] locals = new LocalBuilder[paramTypes.Length]; for (int i = 0; i < paramTypes.Length; i++) { locals[i] = il.DeclareLocal(paramTypes[i], true); } for (int i = 0; i < paramTypes.Length; i++) { il.Emit(OpCodes.Ldarg_1); EmitFastInt(il, i); il.Emit(OpCodes.Ldelem_Ref); EmitCastToReference(il, paramTypes[i]); il.Emit(OpCodes.Stloc, locals[i]); } if (!methodInfo.IsStatic) { il.Emit(OpCodes.Ldarg_0); } for (int i = 0; i < paramTypes.Length; i++) { if (ps[i].ParameterType.IsByRef) { il.Emit(OpCodes.Ldloca_S, locals[i]); } else { il.Emit(OpCodes.Ldloc, locals[i]); } } if (methodInfo.IsStatic) { il.EmitCall(OpCodes.Call, methodInfo, null); } else { il.EmitCall(OpCodes.Callvirt, methodInfo, null); } if (methodInfo.ReturnType == typeof(void)) { il.Emit(OpCodes.Ldnull); } else { EmitBoxIfNeeded(il, methodInfo.ReturnType); } for (int i = 0; i < paramTypes.Length; i++) { if (ps[i].ParameterType.IsByRef) { il.Emit(OpCodes.Ldarg_1); EmitFastInt(il, i); il.Emit(OpCodes.Ldloc, locals[i]); if (locals[i].LocalType.IsValueType) { il.Emit(OpCodes.Box, locals[i].LocalType); } il.Emit(OpCodes.Stelem_Ref); } } il.Emit(OpCodes.Ret); FastInvokeHandlerDelegate invoder = (FastInvokeHandlerDelegate)dynamicMethod.CreateDelegate(typeof(FastInvokeHandlerDelegate)); return(invoder); }
/// <summary> /// Perform an invoke, using a fast delegate. Will try to use the delegate /// cache, so only the first call will be delayed while the delegate is generated. /// </summary> public static object CachedInvoke(MethodInfo methodInfo, object target, object[] parameters) { FastInvokeHandlerDelegate delegateInstance = GetMethodInvoker(methodInfo, true, true); return(delegateInstance.Invoke(target, parameters)); }