/// <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);
        }
Esempio n. 2
0
        /// <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));
        }