コード例 #1
0
        public virtual MethodBuilder CreateMethod(ProxyScope proxyScope, MethodDefinition methodDefinition, MemberInfo member, FieldBuilder memberField, FieldBuilder callerMethodField)
        {
            MethodInfo method = methodDefinition.Method;

            // callback method
            MethodBuilder callbackMethodBuilder = CreateCallbackMethod(proxyScope, methodDefinition.CallbackMethodDefinition);

            // invocation type
            Type invocationType = GetOrCreateInvocationType(proxyScope, methodDefinition, callbackMethodBuilder);

            // method
            MethodBuilder methodBuilder = proxyScope.DefineMethod(methodDefinition.Name, methodDefinition.MethodAttributes);

            methodBuilder.SetReturnType(methodDefinition.ReturnType);

            // parameters
            methodBuilder.DefineGenericParameters(methodDefinition.GenericArguments);
            if (methodDefinition.ParameterDefinitions.Length > 0)
            {
                DefineParameters(methodBuilder, methodDefinition);
            }

            // attributes
            DefineAttributes(methodBuilder, methodDefinition);

            // method body
            var il = methodBuilder.GetILGenerator();

            // locals
            IInterceptorSelector interceptorSelector      = proxyScope.TypeDefinition.Options?.InterceptorSelector;
            FieldBuilder         interceptorSelectorField = null;
            FieldBuilder         interceptorMethodField   = null;

            if (interceptorSelector != null)
            {
                interceptorSelectorField = FindConstructorField(proxyScope, ProxyScope.InterceptorSelectorFieldName);
                interceptorMethodField   = proxyScope.DefineField(methodDefinition.InterceptorSelectorFieldName, typeof(IInterceptor[]), FieldAttributes.Private);
            }
            var          returnType               = methodDefinition.ReturnType;
            Type         targetType               = methodDefinition.TypeDefinition.TargetType;
            Type         localBuilderType         = targetType != null ? targetType : typeof(object);
            LocalBuilder targetLocalBuilder       = il.DeclareLocal(localBuilderType);       // target
            LocalBuilder interceptorsLocalBuilder = il.DeclareLocal(typeof(IInterceptor[])); // interceptors
            LocalBuilder memberLocalBuilder       = il.DeclareLocal(typeof(MemberInfo));     // MemberInfo
            LocalBuilder callerMethodLocalBuilder = il.DeclareLocal(typeof(MethodInfo));     // proxy method
            LocalBuilder proxyLocalBuilder        = il.DeclareLocal(typeof(object));         // proxy
            LocalBuilder parametersLocalBuilder   = il.DeclareLocal(typeof(object[]));       // parameters
            LocalBuilder invocationLocalBuilder   = il.DeclareLocal(invocationType);         // invocation
            LocalBuilder returnValueLocalBuilder  = null;

            if (returnType != typeof(void))
            {
                returnValueLocalBuilder = il.DeclareLocal(returnType);
            }

            FieldBuilder interceptorsField = proxyScope.ConstructorFields[0];

            if (targetType != null)
            {
                FieldBuilder targetField = FindConstructorField(proxyScope, methodDefinition.TypeDefinition.TargetFieldName);
                EmitHelper.StoreFieldToLocal(il, targetField, targetLocalBuilder);
            }

            EmitHelper.StoreFieldToLocal(il, memberField, memberLocalBuilder);
            EmitHelper.StoreFieldToLocal(il, callerMethodField, callerMethodLocalBuilder);
            EmitHelper.StoreThisToLocal(il, proxyLocalBuilder);

            if (interceptorSelector != null)
            {
                LocalBuilder isNullLocal = il.DeclareLocal(typeof(bool));
                Label        isNullLabel = il.DefineLabel();

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, interceptorMethodField);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Stloc, isNullLocal);
                il.Emit(OpCodes.Ldloc, isNullLocal);

                il.Emit(OpCodes.Brfalse_S, isNullLabel);

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, interceptorSelectorField);
                il.Emit(OpCodes.Ldtoken, member.DeclaringType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);
                il.Emit(OpCodes.Ldloc, callerMethodLocalBuilder);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, interceptorsField);
                il.Emit(OpCodes.Callvirt, Methods.SelectInterceptorsMethod);
                il.Emit(OpCodes.Stfld, interceptorMethodField);

                il.MarkLabel(isNullLabel);

                EmitHelper.StoreFieldToLocal(il, interceptorMethodField, interceptorsLocalBuilder);
            }
            else
            {
                EmitHelper.StoreFieldToLocal(il, interceptorsField, interceptorsLocalBuilder);
            }

            StoreArgsToArray(il, methodDefinition.ParameterDefinitions, parametersLocalBuilder);

            EmitHelper.CreateInvocation(il, invocationType, targetLocalBuilder, interceptorsLocalBuilder, memberLocalBuilder, callerMethodLocalBuilder, proxyLocalBuilder, parametersLocalBuilder, invocationLocalBuilder);
            EmitHelper.CallProceed(il, invocationLocalBuilder);

            // set ref parameters values after Proceed called
            SetByRefArgs(il, methodDefinition.ParameterDefinitions, invocationLocalBuilder);

            EmitReturnValue(il, method, invocationLocalBuilder, returnValueLocalBuilder);

            if (method.DeclaringType.IsInterface)
            {
                proxyScope.DefineMethodOverride(methodBuilder, method);
            }

            return(methodBuilder);
        }