Ejemplo n.º 1
0
        private void CreateMethod(ProxyClassBuildingContext classContext, string path, MethodDescription methodDesc)
        {
            var methodBuilder = classContext.Builder.DefineMethod(methodDesc.Name,
                                                                  MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                                  MethodAttributes.NewSlot | MethodAttributes.Virtual);

            var genericTypeParameterBuilders = methodDesc.GenericParameters.Any()
                ? methodBuilder.DefineGenericParameters(methodDesc.GenericParameters.Select(x => x.Name).ToArray())
                : new GenericTypeParameterBuilder[0];
            var genericTypeParameterCodecs = genericTypeParameterBuilders.Select(x => new ProxyMethodGenericArgumentCodec(x)).ToArray();
            var genericArgumentMap         = genericTypeParameterBuilders.ToDictionary(x => x.Name, x => (Type)x);

            var parameterDescriptions         = methodDesc.Parameters.Select(x => x.DeepSubstituteGenerics(genericArgumentMap)).ToArray();
            var parameterTypesAdjustedForRefs = parameterDescriptions.Select(x => x.Way == MethodParameterWay.Val ? x.Type : x.Type.MakeByRefType()).ToArray();
            var allParameterCodecs            = parameterDescriptions.Select(x => new ProxyMethodParameterCodec(x)).ToArray();

            var retvalType = methodDesc.ReturnType.DeepSubstituteGenerics(genericArgumentMap);

            methodBuilder.SetParameters(parameterTypesAdjustedForRefs);
            methodBuilder.SetReturnType(retvalType);
            methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);

            var il = new MyILGenerator(methodBuilder.GetILGenerator());
            var emittingContext = new ProxyMethodEmittingContext(il, classContext.Fields);

            var requestDataArrayVar = il.DeclareLocal(typeof(byte[]));                      // byte[] dataArray

            var requestParametersCodecs = allParameterCodecs.Where(x => x.IsRequestParameter).ToArray();

            if (requestParametersCodecs.Any() || genericTypeParameterBuilders.Any())
            {
                bool haveSizeOnStack = false;
                foreach (var codec in genericTypeParameterCodecs)
                {
                    codec.EmitCalculateSize(emittingContext);                               // stack_0 += CalculateSize(T_i)
                    EmitAddIf(il, ref haveSizeOnStack);
                }
                foreach (var parameter in requestParametersCodecs)
                {
                    parameter.EmitCalculateSize(emittingContext);                           // stack_0 += CalculateSize(arg_i)
                    EmitAddIf(il, ref haveSizeOnStack);
                }

                il.Newarr(typeof(byte));                                                    // dataArray = new byte[stack_0]
                il.Stloc(requestDataArrayVar);
                var pinnedVar = il.PinArray(typeof(byte), requestDataArrayVar);             // var pinned dataPointer = pin(dataArray)
                il.Ldloc(pinnedVar);                                                        // data = dataPointer
                il.Stloc(emittingContext.DataPointerVar);

                foreach (var codec in genericTypeParameterCodecs)
                {
                    codec.EmitEncode(emittingContext);                                      // Encode(T_i, data)
                }
                foreach (var codec in requestParametersCodecs)
                {
                    codec.EmitEncode(emittingContext);                                      // Encode(arg_i, data)
                }
            }
            else
            {
                il.Ldnull();                                                                // dataArray = null
                il.Stloc(requestDataArrayVar);
            }

            il.Ldarg(0);                                                                    // stack_0 = methodCallProcessor
            il.Ldfld(classContext.Fields.Processor);
            il.Ldtoken(classContext.InterfaceType);                                         // stack_1 = typeof(T)
            il.Call(TypeMethods.GetTypeFromHandle);
            il.Ldstr(string.Format("{0}/{1}", path, methodDesc.Name));                      // stack_2 = SuperServicePath/ServiceName/MethodName
            il.Ldarg(0);                                                                    // stack_3 = scope
            il.Ldfld(classContext.Fields.Scope);
            il.Ldloc(requestDataArrayVar);                                                  // stack_4 = dataArray
            il.Ldarg(0);                                                                    // stack_5 = timeoutSettings
            il.Ldfld(classContext.Fields.TimeoutSettings);

            var responseParameterCodecs = allParameterCodecs.Where(x => x.IsResponseParameter).ToArray();

            if (responseParameterCodecs.Any() && methodDesc.RemotingType != MethodRemotingType.Direct)
            {
                throw new ArgumentException(string.Format("Error processing {0} method: only direct methods can have Ref or Out parameters", path));
            }

            switch (methodDesc.RemotingType)
            {
            case MethodRemotingType.Direct:
                EmitProcessDirect(emittingContext, responseParameterCodecs, retvalType);
                break;

            case MethodRemotingType.AsyncVoid:
                EmitProcessAsyncVoid(il);
                break;

            case MethodRemotingType.AsyncWithRetval:
                EmitProcessAsyncWithRetval(classContext, emittingContext, methodDesc.Name, genericTypeParameterBuilders, retvalType);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            il.Ret();
        }