Example #1
0
        private Type CreateProxyClass(Type rootType, Type type, string path)
        {
            var serviceDescription = serviceDescriptionBuilder.Build(type);

            path = path ?? serviceDescription.Name;

            var typeBuilder = moduleBuilder.DefineType("__rpc_proxy_" + type.FullName + "_" + classNameDisambiguator++,
                                                       TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                                                       typeof(object), new[] { type });

            #region Emit Fields
            var processorField = typeBuilder.DefineField("methodCallProcessor", typeof(IOutgoingMethodCallProcessor),
                                                         FieldAttributes.Private | FieldAttributes.InitOnly);
            var scopeField = typeBuilder.DefineField("scope", typeof(string),
                                                     FieldAttributes.Private | FieldAttributes.InitOnly);
            var timeoutSettingsField = typeBuilder.DefineField("timeoutSettings", typeof(TimeoutSettings),
                                                               FieldAttributes.Private | FieldAttributes.InitOnly);
            #endregion

            #region Begin Emit Constructor
            var constructorBuilder = typeBuilder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.Standard, ConstructorParameterTypes);
            var baseConstructor = typeof(object).GetConstructor(Type.EmptyTypes);
            var cil             = constructorBuilder.GetILGenerator();
            cil.Emit(OpCodes.Ldarg_0);
            cil.Emit(OpCodes.Call, baseConstructor);
            cil.Emit(OpCodes.Ldarg_0);
            cil.Emit(OpCodes.Ldarg_1);
            cil.Emit(OpCodes.Stfld, processorField);
            cil.Emit(OpCodes.Ldarg_0);
            cil.Emit(OpCodes.Ldarg_2);
            cil.Emit(OpCodes.Stfld, scopeField);
            cil.Emit(OpCodes.Ldarg_0);
            cil.Emit(OpCodes.Ldarg_3);
            cil.Emit(OpCodes.Stfld, timeoutSettingsField);
            #endregion

            foreach (var subserviceDesc in serviceDescription.Subservices)
            {
                #region Emit Subservice Property
                var proxyClass = CreateProxyClass(rootType, subserviceDesc.Service.Type, path + "/" + subserviceDesc.Name);

                var fieldBuilder = typeBuilder.DefineField("_" + subserviceDesc.Name, proxyClass,
                                                           FieldAttributes.Private | FieldAttributes.InitOnly);

                cil.Emit(OpCodes.Ldarg_0);
                cil.Emit(OpCodes.Ldarg_1);
                cil.Emit(OpCodes.Ldarg_2);
                cil.Emit(OpCodes.Ldarg_3);
                cil.Emit(OpCodes.Newobj, proxyClass.GetConstructor(ConstructorParameterTypes));
                cil.Emit(OpCodes.Stfld, fieldBuilder);

                var methodBuilder = typeBuilder.DefineMethod("get_" + subserviceDesc.Name,
                                                             MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                             MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                                                             subserviceDesc.Service.Type, Type.EmptyTypes);
                methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);
                var il = methodBuilder.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, fieldBuilder);
                il.Emit(OpCodes.Ret);

                var propertyBuilder = typeBuilder.DefineProperty(subserviceDesc.Name,
                                                                 PropertyAttributes.None, subserviceDesc.Service.Type, Type.EmptyTypes);
                propertyBuilder.SetGetMethod(methodBuilder);
                #endregion
            }

            #region End Emit Constructor
            cil.Emit(OpCodes.Ret);
            #endregion

            foreach (var methodDesc in serviceDescription.Methods)
            {
                #region Emit Method
                var parameterTypes = methodDesc.Parameters.Select(x => x.Way == MethodParameterWay.Val ? x.Type : x.Type.MakeByRefType()).ToArray();
                var dynamicMethod  = EmitDynamicMethod(rootType, path, methodDesc, parameterTypes, codecContainer);
                dynamicMethods.Add(dynamicMethod);
                var dynamicMethodPointer = MethodHelpers.ExtractDynamicMethodPointer(dynamicMethod);

                var methodBuilder = typeBuilder.DefineMethod(methodDesc.Name,
                                                             MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                             MethodAttributes.NewSlot | MethodAttributes.Virtual,
                                                             dynamicMethod.ReturnType, parameterTypes);
                methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);

                var il = methodBuilder.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, processorField);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, scopeField);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, timeoutSettingsField);
                for (int i = 0; i < methodDesc.Parameters.Count; i++)
                {
                    il.Emit(OpCodes.Ldarg, i + 1);
                }
                il.Emit_Ldc_IntPtr(dynamicMethodPointer);
                il.EmitCalli(OpCodes.Calli, CallingConventions.Standard,
                             dynamicMethod.ReturnType,
                             dynamicMethod.GetParameters().Select(x => x.ParameterType).ToArray(),
                             null);
                il.Emit(OpCodes.Ret);
                #endregion
            }

            return(typeBuilder.CreateType());
        }