private static void ImplementSharedExecuter(MethodBuilderContext context, MethodInfo initMethod, MethodInfo execMethod)
        {
            FieldBuilder field = null;

            if (initMethod != null)
            {
                field = context.TypeBuilder.DefineField("__methodField_" + context.Method.Name + context.Method.GetHashCode().ToString(), initMethod.ReturnType, FieldAttributes.Private);

                // Load instance for initializer
                context.InitMethodGenerator.Emit(OpCodes.Ldarg_0);
                context.InitMethodGenerator.Emit(OpCodes.Ldarg_0);
                context.InitMethodGenerator.Emit(OpCodes.Ldsfld, context.MethodInfoField);
                context.InitMethodGenerator.EmitCall(OpCodes.Call, initMethod, null); // Call init method
                context.InitMethodGenerator.Emit(OpCodes.Stfld, field);               // Store result in field
            }

            // Create object array to hold all parameters and load on stack
            var parametersArray = context.ExecMethodGenerator.EmitParametersArray(context.Method);

            // Call executer(layer, state, params)
            context.ExecMethodGenerator.Emit(OpCodes.Ldarg_0); // Load instance as first param to execute

            if (field != null)
            {
                context.ExecMethodGenerator.Emit(OpCodes.Ldarg_0);      // Load instance for load field
                context.ExecMethodGenerator.Emit(OpCodes.Ldfld, field); // Load infos array
            }
            else
            {
                context.ExecMethodGenerator.Emit(OpCodes.Ldsfld, context.MethodInfoField);
            }

            context.ExecMethodGenerator.Emit(OpCodes.Ldloc, parametersArray);     // Load params as third param for execute
            context.ExecMethodGenerator.EmitCall(OpCodes.Call, execMethod, null); // Call execute method

            // Handle return value
            if (context.Method.ReturnType == typeof(void))
            {
                context.ExecMethodGenerator.Emit(OpCodes.Pop);
            }
            else if (context.Method.ReturnType.IsValueType)
            {
                context.ExecMethodGenerator.Emit(OpCodes.Unbox_Any, context.Method.ReturnType);
            }
        }
        private static void ImplementTarget(MethodBuilderContext context, string targetMemberName, Func <MethodInfo, MethodInfo> targetMethodSelector)
        {
            // Find target method
            MethodInfo targetMethod = targetMethodSelector(context.Method);

            if (targetMethod == null)
            {
                throw new ArgumentException("Target method for interface method {0} not found.", context.Method.Name);
            }

            // If method is instance, we need to find target instance and load it on stack
            if (!targetMethod.IsStatic)
            {
                MemberInfo getTargetMember = context.BaseClass.GetMember(targetMemberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public).Single();

                context.ExecMethodGenerator.Emit(OpCodes.Ldarg_0);
                if (getTargetMember.MemberType == MemberTypes.Field)
                {
                    context.ExecMethodGenerator.Emit(OpCodes.Ldfld, (FieldInfo)getTargetMember);
                }
                else if (getTargetMember.MemberType == MemberTypes.Property)
                {
                    context.ExecMethodGenerator.EmitCall(OpCodes.Call, ((PropertyInfo)getTargetMember).GetGetMethod(), null);
                }
                else
                {
                    context.ExecMethodGenerator.EmitCall(OpCodes.Call, (MethodInfo)getTargetMember, null);
                }
            }

            // Load all parameters
            for (int i = 1; i <= context.Method.GetParameters().Length; i++)
            {
                context.ExecMethodGenerator.Emit(OpCodes.Ldarg, i);
            }

            // Call method and return
            context.ExecMethodGenerator.EmitCall(OpCodes.Call, targetMethod, null);
            context.ExecMethodGenerator.Emit(OpCodes.Ret);
        }