Emit实现AOP示例

时间:2014-08-03 08:22:20
【文件属性】:

文件名称: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)

网友评论

  • 入门了,谢谢分享
  • 实测,可以使用。但是费了好大劲。 对于方法名相同 参数不同的,都无法成功。求解析。
  • 入门还可以!
  • 可当入门级例子
  • 才是读感觉不是太懂这个,不过时间还长
  • 动态植入技术不明觉厉啊
  • 东西不错,就是看着比较费劲。可能是基础知识掌握不够把
  • 新手,完全看不懂。头大。。。
  • 轻量,比较简单,适合学习emit, 实用上可能还要精进些
  • 谢谢根据你的例子 我自己写了 il代码
  • 真好在研究AOP,这种动态的方式是值得学习的。
  • 很受启发!
  • 可当入门级例子
  • 简单的例子,可以加深对emit的理解。初学emit的可以看看。
  • 推荐新人学习,内容可以,很不错,适合新手!