private static void EmitDispatch(DynamicTypeWrapper.FinishContext context, TypeWrapper[] args, TypeBuilder tb, MethodWrapper interfaceMethod, TypeWrapper[] implParameters,
                                         ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, FieldBuilder[] capturedFields)
        {
            MethodBuilder mb = interfaceMethod.GetDefineMethodHelper().DefineMethod(context.TypeWrapper, tb, interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final);

            if (interfaceMethod.Name != interfaceMethod.RealName)
            {
                tb.DefineMethodOverride(mb, (MethodInfo)interfaceMethod.GetMethod());
            }
            CodeEmitter ilgen = CodeEmitter.Create(mb);

            for (int i = 0; i < capturedFields.Length; i++)
            {
                ilgen.EmitLdarg(0);
                OpCode opc = OpCodes.Ldfld;
                if (i == 0 && args[0].IsGhost)
                {
                    switch (implMethod.Kind)
                    {
                    case ClassFile.RefKind.invokeInterface:
                    case ClassFile.RefKind.invokeVirtual:
                    case ClassFile.RefKind.invokeSpecial:
                        opc = OpCodes.Ldflda;
                        break;
                    }
                }
                ilgen.Emit(opc, capturedFields[i]);
            }
            for (int i = 0, count = interfaceMethod.GetParameters().Length, k = capturedFields.Length; i < count; i++)
            {
                ilgen.EmitLdarg(i + 1);
                TypeWrapper Ui = interfaceMethod.GetParameters()[i];
                TypeWrapper Ti = instantiatedMethodType.GetArgTypes()[i];
                TypeWrapper Aj = implParameters[i + k];
                if (Ui == PrimitiveTypeWrapper.BYTE)
                {
                    ilgen.Emit(OpCodes.Conv_I1);
                }
                if (Ti != Ui)
                {
                    if (Ti.IsGhost)
                    {
                        Ti.EmitConvStackTypeToSignatureType(ilgen, Ui);
                    }
                    else if (Ui.IsGhost)
                    {
                        Ui.EmitConvSignatureTypeToStackType(ilgen);
                    }
                    else
                    {
                        Ti.EmitCheckcast(ilgen);
                    }
                }
                if (Ti != Aj)
                {
                    if (Ti.IsPrimitive && !Aj.IsPrimitive)
                    {
                        Boxer.EmitBox(ilgen, Ti);
                    }
                    else if (!Ti.IsPrimitive && Aj.IsPrimitive)
                    {
                        TypeWrapper primitive = GetPrimitiveFromWrapper(Ti);
                        Boxer.EmitUnbox(ilgen, primitive, false);
                        if (primitive == PrimitiveTypeWrapper.BYTE)
                        {
                            ilgen.Emit(OpCodes.Conv_I1);
                        }
                    }
                    else if (Aj == PrimitiveTypeWrapper.LONG)
                    {
                        ilgen.Emit(OpCodes.Conv_I8);
                    }
                    else if (Aj == PrimitiveTypeWrapper.FLOAT)
                    {
                        ilgen.Emit(OpCodes.Conv_R4);
                    }
                    else if (Aj == PrimitiveTypeWrapper.DOUBLE)
                    {
                        ilgen.Emit(OpCodes.Conv_R8);
                    }
                }
            }
            switch (implMethod.Kind)
            {
            case ClassFile.RefKind.invokeVirtual:
            case ClassFile.RefKind.invokeInterface:
                ((MethodWrapper)implMethod.Member).EmitCallvirt(ilgen);
                break;

            case ClassFile.RefKind.newInvokeSpecial:
                ((MethodWrapper)implMethod.Member).EmitNewobj(ilgen);
                break;

            case ClassFile.RefKind.invokeStatic:
            case ClassFile.RefKind.invokeSpecial:
                ((MethodWrapper)implMethod.Member).EmitCall(ilgen);
                break;

            default:
                throw new InvalidOperationException();
            }
            TypeWrapper Ru = interfaceMethod.ReturnType;
            TypeWrapper Ra = GetImplReturnType(implMethod);
            TypeWrapper Rt = instantiatedMethodType.GetRetType();

            if (Ra == PrimitiveTypeWrapper.BYTE)
            {
                ilgen.Emit(OpCodes.Conv_I1);
            }
            if (Ra != Ru)
            {
                if (Ru == PrimitiveTypeWrapper.VOID)
                {
                    ilgen.Emit(OpCodes.Pop);
                }
                else if (Ra.IsGhost)
                {
                    Ra.EmitConvSignatureTypeToStackType(ilgen);
                }
                else if (Ru.IsGhost)
                {
                    Ru.EmitConvStackTypeToSignatureType(ilgen, Ra);
                }
            }
            if (Ra != Rt)
            {
                if (Rt.IsPrimitive)
                {
                    if (Rt == PrimitiveTypeWrapper.VOID)
                    {
                        // already popped
                    }
                    else if (!Ra.IsPrimitive)
                    {
                        TypeWrapper primitive = GetPrimitiveFromWrapper(Ra);
                        if (primitive != null)
                        {
                            Boxer.EmitUnbox(ilgen, primitive, false);
                        }
                        else
                        {
                            // If Q is not a primitive wrapper, cast Q to the base Wrapper(S); for example Number for numeric types
                            EmitConvertingUnbox(ilgen, Rt);
                        }
                    }
                    else if (Rt == PrimitiveTypeWrapper.LONG)
                    {
                        ilgen.Emit(OpCodes.Conv_I8);
                    }
                    else if (Rt == PrimitiveTypeWrapper.FLOAT)
                    {
                        ilgen.Emit(OpCodes.Conv_R4);
                    }
                    else if (Rt == PrimitiveTypeWrapper.DOUBLE)
                    {
                        ilgen.Emit(OpCodes.Conv_R8);
                    }
                }
                else if (Ra.IsPrimitive)
                {
                    Boxer.EmitBox(ilgen, GetPrimitiveFromWrapper(Rt));
                }
                else
                {
                    Rt.EmitCheckcast(ilgen);
                }
            }
            ilgen.EmitTailCallPrevention();
            ilgen.Emit(OpCodes.Ret);
            ilgen.DoEmit();
        }