private void AddVoidMethodImplementation(
            TypeBuilder classBuilder,
            int interfaceDescriptionId,
            MethodDescription methodDescription,
            MethodBodyTypes methodBodyTypes,
            string interfaceName)
        {
            var interfaceMethod = methodDescription.MethodInfo;

            var methodBuilder = CodeBuilderUtils.CreateExplitInterfaceMethodBuilder(
                classBuilder,
                interfaceMethod);

            var ilGen = methodBuilder.GetILGenerator();

            // Create Wrapped Request
            LocalBuilder wrappedRequestBody =
                CreateWrappedRequestBody(methodDescription, methodBodyTypes, ilGen, methodDescription.MethodInfo.GetParameters());

            this.AddVoidMethodImplementation(
                ilGen,
                interfaceDescriptionId,
                methodDescription,
                wrappedRequestBody,
                interfaceName);

            ilGen.Emit(OpCodes.Ret);
        }
        private void AddAsyncMethodImplementation(
            TypeBuilder classBuilder,
            int interfaceId,
            MethodDescription methodDescription,
            MethodBodyTypes methodBodyTypes,
            string interfaceName)
        {
            var interfaceMethod = methodDescription.MethodInfo;
            var parameters      = interfaceMethod.GetParameters();
            var methodBuilder   = CodeBuilderUtils.CreateExplitInterfaceMethodBuilder(
                classBuilder,
                interfaceMethod);
            var ilGen           = methodBuilder.GetILGenerator();
            var parameterLength = parameters.Length;

            if (methodDescription.HasCancellationToken)
            {
                // Cancellation token is tracked locally and should not be serialized and sent
                // as a part of the request body.
                parameterLength -= 1;
            }

            LocalBuilder requestMessage = null;

            if (parameterLength > 0)
            {
                // Create Wrapped Message
                // create requestBody and assign the values to its field from the arguments
                var wrappedRequestBody = CreateWrappedRequestBody(methodDescription, methodBodyTypes, ilGen, parameters);

                // create IServiceRemotingRequestMessageBody message
                requestMessage = this.CreateRequestRemotingMessageBody(methodDescription, interfaceName, ilGen, parameterLength, wrappedRequestBody);

                // Check if requestMessage is not implementing WrappedMessage , then call SetParam
                this.SetParameterIfNeeded(ilGen, requestMessage, parameterLength, parameters);
            }

            var objectTask = ilGen.DeclareLocal(typeof(Task <IActorResponseMessageBody>));

            // call the base InvokeMethodAsync method
            ilGen.Emit(OpCodes.Ldarg_0);                       // base
            ilGen.Emit(OpCodes.Ldc_I4, interfaceId);           // interfaceId
            ilGen.Emit(OpCodes.Ldc_I4, methodDescription.Id);  // methodId
            ilGen.Emit(OpCodes.Ldstr, methodDescription.Name); // method name

            if (requestMessage != null)
            {
                ilGen.Emit(OpCodes.Ldloc, requestMessage);
            }
            else
            {
                ilGen.Emit(OpCodes.Ldnull);
            }

            // Cancellation token argument
            if (methodDescription.HasCancellationToken)
            {
                // Last argument should be the cancellation token
                var cancellationTokenArgIndex = parameters.Length;
                ilGen.Emit(OpCodes.Ldarg, cancellationTokenArgIndex);
            }
            else
            {
                var cancellationTokenNone = typeof(CancellationToken).GetMethod("get_None");
                ilGen.EmitCall(OpCodes.Call, cancellationTokenNone, null);
            }

            ilGen.EmitCall(OpCodes.Call, this.invokeAsyncMethodInfo, null);
            ilGen.Emit(OpCodes.Stloc, objectTask);

            // call the base method to get the continuation task and
            // convert the response body to return value when the task is finished
            if (TypeUtility.IsTaskType(methodDescription.ReturnType) &&
                methodDescription.ReturnType.GetTypeInfo().IsGenericType)
            {
                var retvalType = methodDescription.ReturnType.GetGenericArguments()[0];

                ilGen.Emit(OpCodes.Ldarg_0);                      // base pointer
                ilGen.Emit(OpCodes.Ldc_I4, interfaceId);          // interfaceId
                ilGen.Emit(OpCodes.Ldc_I4, methodDescription.Id); // methodId
                ilGen.Emit(OpCodes.Ldloc, objectTask);            // task<IServiceRemotingResponseMessageBody>
                ilGen.Emit(OpCodes.Call, this.continueWithResultMethodInfo.MakeGenericMethod(retvalType));
                ilGen.Emit(OpCodes.Ret);                          // return base.ContinueWithResult<TResult>(task);
            }
            else
            {
                ilGen.Emit(OpCodes.Ldarg_0);           // base pointer
                ilGen.Emit(OpCodes.Ldloc, objectTask); // task<object>
                ilGen.Emit(OpCodes.Call, this.continueWithMethodInfo);
                ilGen.Emit(OpCodes.Ret);               // return base.ContinueWith(task);
            }
        }