Exemple #1
0
        /// <summary>
        /// Returns an instruction to call the specified delegate.
        /// </summary>
        /// <typeparam name="T">The delegate type to emit.</typeparam>
        /// <param name="action">The delegate to emit.</param>
        /// <returns>The instruction to </returns>
        public static CodeInstruction EmitDelegate <T>(T action) where T : Delegate
        {
            if (action.Method.IsStatic && action.Target == null)
            {
                return(new CodeInstruction(OpCodes.Call, action.Method));
            }

            var paramTypes = action.Method.GetParameters().Select(x => x.ParameterType).ToArray();

            var dynamicMethod = new DynamicMethodDefinition(action.Method.Name,
                                                            action.Method.ReturnType,
                                                            paramTypes);

            var il = dynamicMethod.GetILGenerator();

            var targetType = action.Target.GetType();

            var preserveContext = action.Target != null && targetType.GetFields().Any(x => !x.IsStatic);

            if (preserveContext)
            {
                var currentDelegateCounter = _delegateCounter++;

                _delegateCache[currentDelegateCounter] = action;

                var cacheField = AccessTools.Field(typeof(Transpilers), nameof(_delegateCache));

                var getMethod = AccessTools.Method(typeof(Dictionary <int, Delegate>), "get_Item");

                il.Emit(OpCodes.Ldsfld, cacheField);
                il.Emit(OpCodes.Ldc_I4, currentDelegateCounter);
                il.Emit(OpCodes.Callvirt, getMethod);
            }
            else
            {
                if (action.Target == null)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    il.Emit(OpCodes.Newobj, AccessTools.FirstConstructor(targetType, x => x.GetParameters().Length == 0 && !x.IsStatic));
                }

                il.Emit(OpCodes.Ldftn, action.Method);
                il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) }));
            }


            for (var i = 0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg_S, (short)i);
            }

            il.Emit(OpCodes.Callvirt, typeof(T).GetMethod("Invoke"));

            il.Emit(OpCodes.Ret);

            return(new CodeInstruction(OpCodes.Call, dynamicMethod.Generate()));
        }
Exemple #2
0
        /// <summary>Returns an instruction to call the specified closure</summary>
        /// <typeparam name="T">The delegate type to emit</typeparam>
        /// <param name="closure">The closure that defines the method to call</param>
        /// <returns>A <see cref="CodeInstruction"/> that calls the closure as a method</returns>
        ///
        public static CodeInstruction CallClosure <T>(T closure) where T : Delegate
        {
            if (closure.Method.IsStatic && closure.Target == null)
            {
                return(new CodeInstruction(OpCodes.Call, closure.Method));
            }

            var parameters    = closure.Method.GetParameters().Select(x => x.ParameterType).ToArray();
            var closureMethod = new DynamicMethodDefinition(closure.Method.Name, closure.Method.ReturnType, parameters);

            var il         = closureMethod.GetILGenerator();
            var targetType = closure.Target.GetType();

            var preserveContext = closure.Target != null && targetType.GetFields().Any(x => !x.IsStatic);

            if (preserveContext)
            {
                var n = State.closureCache.Count;
                State.closureCache[n] = closure;
                il.Emit(OpCodes.Ldsfld, AccessTools.Field(typeof(Transpilers), nameof(State.closureCache)));
                il.Emit(OpCodes.Ldc_I4, n);
                il.Emit(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Dictionary <int, Delegate>), "Item"));
            }
            else
            {
                if (closure.Target == null)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    il.Emit(OpCodes.Newobj, AccessTools.FirstConstructor(targetType, x => x.IsStatic == false && x.GetParameters().Length == 0));
                }

                il.Emit(OpCodes.Ldftn, closure.Method);
                il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) }));
            }

            for (var i = 0; i < parameters.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
            }

            il.Emit(OpCodes.Callvirt, AccessTools.Method(typeof(T), nameof(Action.Invoke)));
            il.Emit(OpCodes.Ret);

            return(new CodeInstruction(OpCodes.Call, closureMethod.Generate()));
        }