예제 #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);
        }
예제 #2
0
        /// <summary>
        /// 在代理类中定义一个调用拦截器的方法。
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        private static DynamicMethodBuilder DefineInterceptMethod(DynamicTypeBuilder builder)
        {
            #region 方法原型

            /*
             * private void <Aspect>_Intercept(List<IInterceptor> interceptors, InterceptCallInfo callInfo, InterceptType interceptType)
             * {
             *  callInfo.InterceptType = interceptType;
             *  for (int i = 0; i < interceptors.Count; i++)
             *  {
             *      interceptors[i].Intercept(callInfo);
             *  }
             * }
             */
            #endregion
            var callMethod = builder.DefineMethod(
                string.Concat(AOP_PREFIX, "Intercept"),
                null,
                new[] { typeof(List <IInterceptor>), typeof(InterceptCallInfo), typeof(InterceptType) },
                VisualDecoration.Private, ilCoding: ctx =>
            {
                var l1 = ctx.Emitter.DefineLabel();
                var l2 = ctx.Emitter.DefineLabel();
                ctx.Emitter.DeclareLocal(typeof(int));
                ctx.Emitter
                .ldarg_2
                .ldarg_3
                .call(InterceptCache.CallInfoSetInterceptType)
                .ldc_i4_0
                .stloc_0
                .br_s(l2)
                .MarkLabel(l1)
                .ldarg_1
                .ldloc_0
                .call(InterceptCache.InterceptorsGetItem)
                .ldarg_2
                .call(InterceptCache.InterceptorIntercept)
                .ldloc_0
                .ldc_i4_1
                .add
                .stloc_0
                .MarkLabel(l2)
                .ldloc_0
                .ldarg_1
                .call(InterceptCache.InterceptorsGetCount)
                .blt_s(l1)
                .ret();
            });

            callMethod.DefineParameter("interceptors");
            callMethod.DefineParameter("callInfo");
            callMethod.DefineParameter("interceptType");

            return(callMethod);
        }
예제 #3
0
        /// <summary>
        /// 向属性的 get 方法中注入代码。
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="field"></param>
        /// <param name="globalIntercepts"></param>
        /// <param name="interceptMethod"></param>
        /// <param name="property"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        private static DynamicMethodBuilder InjectGetMethod(DynamicTypeBuilder builder, DynamicFieldBuilder field, IList <InterceptAttribute> globalIntercepts, DynamicMethodBuilder interceptMethod, PropertyInfo property, MethodInfo method)
        {
            var attributes  = property.GetCustomAttributes <InterceptAttribute>(true).Union(globalIntercepts);
            var isInterface = builder.BaseType == typeof(object);

            var initMethod = DefineInitializeMethod(builder, method.Name);

            var parameters    = method.GetParameters();
            var methodBuilder = builder.DefineMethod(
                method.Name,
                method.ReturnType,
                (from s in parameters select s.ParameterType).ToArray(),
                ilCoding: ctx =>
            {
                var lblCancel = ctx.Emitter.DefineLabel();
                var lblRet    = ctx.Emitter.DefineLabel();
                ctx.Emitter.DeclareLocal();
                ctx.Emitter.DeclareLocal(property.PropertyType);
                ctx.Emitter.InitInterceptors(attributes);
                ctx.Emitter.InitLocal(property);
                ctx.Emitter.BeginExceptionBlock();
                ctx.Emitter.CallInitialize(initMethod)
                .CallInterceptors(interceptMethod, InterceptType.BeforeGetValue)
                .ldloc(STACK_CALLINFO_INDEX)
                .callvirt(InterceptCache.CallInfoGetCancel).brtrue_s(lblCancel)
                .Assert(isInterface, c => c.ldarg_0.ldfld(field.FieldBuilder), c => c.ldarg_0.call(method))
                .SetReturnValue(method.ReturnType)
                .MarkLabel(lblCancel)
                .CallInterceptors(interceptMethod, InterceptType.AfterGetValue)
                .BeginCatchBlock(typeof(Exception))
                .SetException()
                .CallInterceptors(interceptMethod, InterceptType.Catching)
                .Assert(AllowThrowException(attributes), e => e.ThrowException())
                .BeginFinallyBlock()
                .CallInterceptors(interceptMethod, InterceptType.Finally)
                .EndExceptionBlock()
                .GetReturnValue(property.PropertyType, lblRet);
            });

            foreach (var par in parameters)
            {
                methodBuilder.DefineParameter(par.Name);
            }

            return(methodBuilder);
        }
예제 #4
0
        /// <summary>
        /// 向方法体内注入代码。
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="globalIntercepts"></param>
        /// <param name="interceptMethod">前面定义的拦截方法体。</param>
        /// <param name="method">所要注入的方法。</param>
        /// <returns></returns>
        private static DynamicMethodBuilder InjectMethod(DynamicTypeBuilder builder, IList <InterceptAttribute> globalIntercepts, DynamicMethodBuilder interceptMethod, MethodInfo method)
        {
            var attributes  = method.GetCustomAttributes <InterceptAttribute>(true).Union(globalIntercepts);
            var isInterface = builder.BaseType == typeof(object);

            var initMethod = DefineInitializeMethod(builder, method.Name);

            #region 方法原型
            // var list = new List<InterceptAttribute>();
            // list.Add(new MyInterceptAttribute());
            // var info = new InterceptCallInfo();
            // info.Target = this;
            // info.Member = MethodInfo.GetCurrentMethod().GetBaseDefinition();
            // info.Arguments = new object[] {  };
            // try
            // {
            //     <Aspect>_方法_Initialize();
            //     <Aspect>_Intercept(list, info, InterceptType.BeforeMethodCall);
            //     if (!info.Cancel)
            //     {
            //         base.方法(); //如果有返回  info.ReturnValue = base.方法();
            //     }
            //     info.Arguments = new object[] {  };
            //     <Aspect>_Intercept(list, info, InterceptType.AfterMethodCall);
            // }
            // catch (Exception exp)
            // {
            //     info.Exception = exp;
            //     <Aspect>_Intercept(list, info, InterceptType.Catching);
            //     //如果需要抛出 throw exp;
            // }
            // finally
            // {
            //     <Aspect>_Intercept(list, info, InterceptType.Finally);
            // }
            // //如果返回
            // if (info.ReturnValue == null)
            // {
            //     return (bool)typeof(bool).GetDefaultValue();
            // }
            // else
            // {
            //     return (bool)info.ReturnValue;
            // };
            #endregion
            var parameters    = method.GetParameters();
            var methodBuilder = builder.DefineMethod(
                method.Name,
                method.ReturnType,
                (from s in parameters select s.ParameterType).ToArray(),
                ilCoding: ctx =>
            {
                var isReturn  = method.ReturnType != typeof(void);
                var lblCancel = ctx.Emitter.DefineLabel();
                var lblRet    = ctx.Emitter.DefineLabel();
                ctx.Emitter.DeclareLocal();
                ctx.Emitter.Assert(isReturn, e => e.DeclareLocal(method.ReturnType));
                ctx.Emitter.InitInterceptors(attributes);
                ctx.Emitter.InitLocal(method, method);
                ctx.Emitter.BeginExceptionBlock();
                ctx.Emitter.CallInitialize(initMethod)
                .CallInterceptors(interceptMethod, InterceptType.BeforeMethodCall)
                .ldloc(STACK_CALLINFO_INDEX)
                .callvirt(InterceptCache.CallInfoGetCancel).brtrue_s(lblCancel)
                .Assert(!isInterface, c => c.CallBaseMethod(method)
                        .Assert(isReturn, e => e.SetReturnValue(method.ReturnType)))
                .MarkLabel(lblCancel)
                .SetArguments(method)
                .CallInterceptors(interceptMethod, InterceptType.AfterMethodCall)
                .BeginCatchBlock(typeof(Exception))
                .SetException()
                .CallInterceptors(interceptMethod, InterceptType.Catching)
                .Assert(AllowThrowException(attributes), e => e.ThrowException())
                .BeginFinallyBlock()
                .CallInterceptors(interceptMethod, InterceptType.Finally)
                .EndExceptionBlock()
                .Assert(isReturn, e1 => e1.GetReturnValue(method.ReturnType, lblRet), e1 => e1.ret());
            });

            foreach (var par in parameters)
            {
                methodBuilder.DefineParameter(par.Name, par.IsOut, par.DefaultValue != DBNull.Value, par.DefaultValue);
            }

            return(methodBuilder);
        }
예제 #5
0
        /// <summary>
        /// 为每一个拦截的方法定义一个初始化上下文的方法。
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="methodName">所要拦截的方法。</param>
        /// <returns></returns>
        private static DynamicMethodBuilder DefineInitializeMethod(DynamicTypeBuilder builder, string methodName)
        {
            #region 方法原型

            /*
             * private void <Aspect>_MethodName_Initialize(List<IInterceptor> interceptors)
             * {
             *  if (!this.<Aspect>_TestContext_Initialized)
             *  {
             *      List<InterceptAttribute> list = new List<InterceptAttribute>();
             *      InterceptAttribute item = new CustomInterceptAttribute {
             *          Name = "测试",
             *          Version = 12,
             *          ValueType = typeof(TestClass),
             *          InterceptorType = typeof(TestInterceptor4),
             *          AllowThrowException = true
             *      };
             *      list.Add(item);
             *      for (int i = 0; i < interceptors.Count; i++)
             *      {
             *          InterceptContext context = new InterceptContext {
             *              Attribute = list[i],
             *              Target = this
             *          };
             *          interceptors[i].Initialize(context);
             *      }
             *      this.<Aspect>_TestContext_Initialized = true;
             *  }
             * }
             */
            #endregion
            var fieldBuilder = builder.TypeBuilder.DefineField(
                string.Concat(AOP_PREFIX, methodName, "_Initialized"),
                typeof(bool),
                FieldAttributes.Private);

            var callMethod = builder.DefineMethod(
                string.Concat(AOP_PREFIX, methodName, "_Initialize"),
                null,
                new[] { typeof(List <IInterceptor>), typeof(InterceptCallInfo) },
                VisualDecoration.Private,
                ilCoding: ctx =>
            {
                var l1 = ctx.Emitter.DefineLabel();
                var l2 = ctx.Emitter.DefineLabel();
                var l3 = ctx.Emitter.DefineLabel();
                ctx.Emitter.DeclareLocal(typeof(int));
                ctx.Emitter.DeclareLocal(typeof(object[]));
                ctx.Emitter.DeclareLocal(typeof(InterceptContext));
                ctx.Emitter.DeclareLocal(typeof(InterceptAttribute));
                ctx.Emitter
                .ldarg_0
                .ldfld(fieldBuilder)
                .ldc_bool(true)
                .beq(l3)
                .ldarg_2
                .call(InterceptCache.MethodAllGetAttributes)
                .stloc_1
                .ldc_i4_0
                .stloc_0
                .br_s(l2)
                .MarkLabel(l1)
                .newobj(typeof(InterceptContext))
                .stloc_2
                .ldloc_2
                .ldloc_1
                .ldloc_0
                .ldelem_ref
                .castType(typeof(InterceptAttribute))
                .callvirt(InterceptCache.InterceptContextSetAttribute)
                .ldloc_2
                .ldarg_0
                .callvirt(InterceptCache.CallInfoSetTarget)
                .ldarg_1
                .ldloc_0
                .call(InterceptCache.InterceptorsGetItem)
                .ldloc_2
                .callvirt(InterceptCache.InterceptorInitialize)
                .ldloc_0
                .ldc_i4_1
                .add
                .stloc_0
                .MarkLabel(l2)
                .ldloc_0
                .ldarg_1
                .call(InterceptCache.InterceptorsGetCount)
                .blt_s(l1)
                .ldarg_0
                .ldc_bool(true)
                .stfld(fieldBuilder)
                .MarkLabel(l3)
                .ret();
            });

            callMethod.DefineParameter("interceptors");
            callMethod.DefineParameter("callInfo");
            return(callMethod);
        }
예제 #6
0
        /// <inheritdoc />
        public override TypeInfo Generate()
        {
            // Create backing field as:
            // private string assemblyName;
            var assemblyNameField =
                DynamicTypeBuilder.DefineField("assemblyName", typeof(string), FieldAttributes.Private);

            // Create ctor as:
            // public IgnoresAccessChecksToAttribute(string)
            var constructorBuilder = DynamicTypeBuilder.DefineConstructor(MethodAttributes.Public,
                                                                          CallingConventions.HasThis,
                                                                          new[] { assemblyNameField.FieldType });

            var il = constructorBuilder.GetILGenerator();

            // Create ctor body as:
            // this.assemblyName = {ctor parameter 0}
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg, 1);
            il.Emit(OpCodes.Stfld, assemblyNameField);

            // return
            il.Emit(OpCodes.Ret);

            // Define property as:
            // public string AssemblyName {get { return this.assemblyName; } }

            // ReSharper disable once UnusedVariable
            var getterPropertyBuilder = DynamicTypeBuilder.DefineProperty(
                "AssemblyName",
                PropertyAttributes.None,
                CallingConventions.HasThis,
                returnType: typeof(string),
                parameterTypes: null);

            var getterMethodBuilder = DynamicTypeBuilder.DefineMethod(
                "get_AssemblyName",
                MethodAttributes.Public,
                CallingConventions.HasThis,
                returnType: typeof(string),
                parameterTypes: null);

            // Generate body:
            // return this.assemblyName;
            il = getterMethodBuilder.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, assemblyNameField);
            il.Emit(OpCodes.Ret);

            // Generate the AttributeUsage attribute for this attribute type:
            // [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
            var attributeUsageTypeInfo = typeof(AttributeUsageAttribute).GetTypeInfo();

            // Find the ctor that takes only AttributeTargets
            var attributeUsageConstructorInfo =
                attributeUsageTypeInfo.DeclaredConstructors
                .Single(c => c.GetParameters().Length == 1 &&
                        c.GetParameters()[0].ParameterType == typeof(AttributeTargets));

            // Find the property to set AllowMultiple
            var allowMultipleProperty =
                attributeUsageTypeInfo.DeclaredProperties
                .Single(f => string.Equals(f.Name, "AllowMultiple"));

            // Create a builder to construct the instance via the ctor and property
            var customAttributeBuilder =
                new CustomAttributeBuilder(attributeUsageConstructorInfo,
                                           new object[] { AttributeTargets.Assembly },
                                           new[] { allowMultipleProperty },
                                           new object[] { true });

            // Attach this attribute instance to the newly defined attribute type
            DynamicTypeBuilder.SetCustomAttribute(customAttributeBuilder);

            // Make the TypeInfo real so the constructor can be used.
            return(DynamicTypeBuilder.CreateTypeInfo());
        }