文件名称:Emit实现AOP示例
文件大小:33KB
文件格式:ZIP
更新时间:2014-08-03 08:22:20
C# Emit AOP
纯手工打造Emit实现AOP private static void OverrideMethods(TypeBuilder tb, MethodInfo method) { if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return; Type[] paramTypes = GetParameterTypes(method); MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; MethodBuilder mb = tb.DefineMethod(method.Name, attr, method.ReturnType, paramTypes); LocalBuilder result = null; ILGenerator il = mb.GetILGenerator(); bool is_void = method.ReturnType != typeof(void); if (is_void == false) result = il.DeclareLocal(method.ReturnType); object[] attrs = method.GetCustomAttributes(typeof(AspectAttribute), false); if (attrs != null) { //初始化所有当前方法用到的参数object[] CreateLocalParameterArr(il, paramTypes); //初始化AspectContext Type ctxType = typeof(AspectContext); ConstructorInfo info = ctxType.GetConstructor(Type.EmptyTypes); var ctx = il.DeclareLocal(ctxType); il.Emit(OpCodes.Newobj, info); il.Emit(OpCodes.Stloc, ctx); //给AspectContext的参数值属性ParameterArgs赋值 var propMethod = ctxType.GetMethod("set_ParameterArgs"); il.Emit(OpCodes.Ldloc, ctx); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, propMethod); int m = attrs.Length; LocalBuilder[] lbs = new LocalBuilder[m]; MethodInfo[] endInvokeMethods = new MethodInfo[m]; //初始化标记的横切对象,并调用横切对象的BeforeInvoke方法 for (int i = 0; i < m; i++) { var tmpType = attrs[i].GetType(); var aspect = il.DeclareLocal(tmpType); ConstructorInfo tmpInfo = tmpType.GetConstructor(Type.EmptyTypes); il.Emit(OpCodes.Newobj, tmpInfo); il.Emit(OpCodes.Stloc, aspect); var before_invoke_method = tmpType.GetMethod("BeforeInvoke"); endInvokeMethods[i] = tmpType.GetMethod("AfterInvoke"); il.Emit(OpCodes.Ldloc, aspect); il.Emit(OpCodes.Ldloc, ctx); il.Emit(OpCodes.Callvirt, before_invoke_method); il.Emit(OpCodes.Nop); lbs[i] = aspect; } //类对象,参数值依次入栈 for (int i = 0; i <= paramTypes.Length; i++) il.Emit(OpCodes.Ldarg, i); //调用基类的方法 il.Emit(OpCodes.Call, method); //如果有返回值,保存返回值到局部变量 if (is_void == false) il.Emit(OpCodes.Stloc, result); //调用横切对象的AfterInvoke方法 for (int i = 0; i < m; i++) { il.Emit(OpCodes.Ldloc, lbs[i]); il.Emit(OpCodes.Ldloc, ctx); il.Emit(OpCodes.Callvirt, endInvokeMethods[i]); il.Emit(OpCodes.Nop); } //如果有返回值,则把返回值压栈 if (is_void == false) il.Emit(OpCodes.Ldloc, result); //返回 il.Emit(OpCodes.Ret); } }
【文件预览】:
ConsoleApp
----bin()
--------Debug()
----obj()
--------Debug()
----Properties()
--------AssemblyInfo.cs(1KB)
----Program.cs(9KB)
----ConsoleApp.csproj(2KB)