예제 #1
0
        /// <summary>
        /// Добавляет к типу прокси реализацию метода.
        /// </summary>
        /// <param name="method">Исходный метод.</param>
        /// <returns>Динамический метод прокси.</returns>
        private MethodBuilder ImplementMethod(MethodInfo method)
        {
            var parameters    = method.GetParameters();
            var paramTypes    = ParameterConverter.GetTypes(parameters);
            var proxiedMethod = DynamicTypeBuilder.DefineMethod(method.Name,
                                                                MethodAttributes.Public | MethodAttributes.Virtual,
                                                                method.ReturnType, paramTypes);

            MakeGeneric(method, proxiedMethod);

            var ilGenerator       = proxiedMethod.GetILGenerator();
            var parametersEmitter = new ParametersEmitter(ilGenerator, paramTypes);
            var packedArgsEmitter = new PackedArgumentsEmitter(ilGenerator);

            ilGenerator.Emit(OpCodes.Nop);

            packedArgsEmitter.EmitProxy();

            // Обобщенные параметры будут известны только во время вызова
            // поэтому заранее собрать делегат не выйдетю
            var methodLambda = method.ContainsGenericParameters
                ? new ExtendedMethodInfo(method, null)
                : new ExtendedMethodInfo(method, Expressions.CreateMethodCall(method));

            var token = _methodLinkStore.CreateToken(methodLambda);

            packedArgsEmitter.EmitMethodToken(token);

            var argumentsEmitter = packedArgsEmitter.EmitArguments(parameters, parametersEmitter);

            if (method.ContainsGenericParameters)
            {
                packedArgsEmitter.EmitGenericArguments(method.GetGenericArguments());
            }

            ilGenerator.Emit(OpCodes.Ldarg_0);
            ilGenerator.Emit(OpCodes.Ldfld, _invokeDelegateField);
            packedArgsEmitter.EmitLoad();
            ilGenerator.Emit(OpCodes.Call, MethodReferences.ActionOfObjectArrayInvoke);

            // Странный блок, не уверен что он нужен.
            for (var i = 0; i < parameters.Length; i++)
            {
                // ReSharper disable once InvertIf
                if (parameters[i].ParameterType.IsByRef)
                {
                    parametersEmitter.EmitBeginSet(i);
                    argumentsEmitter.EmitGet(i);
                    parametersEmitter.EmitEndSet(i, typeof(object));
                }
            }

            packedArgsEmitter.EmitReturnValue(method.ReturnType);

            DynamicTypeBuilder.DefineMethodOverride(proxiedMethod, method);
            return(proxiedMethod);
        }