/// <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())); }