/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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()); }