C#利用Emit反射实现AOP,以及平台化框架封装思路
C#利用Emit反射实现AOP,以及平台化框架封装思路
这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路。
首先是主函数:

static void Main(string[] args)
{
RealClass proxy = (RealClass)DynamicProxyBuilder.Wrap(typeof(RealClass));
proxy.Test(); Console.ReadKey();
}

用一个动态代理Builder包装了真实的被代理类,这是被代理类:

public class RealClass
{
public RealClass() { } //必须是虚方法
public virtual bool Test()
{
return false;
}
}

我们需要在Test执行前后做一些事情,也就是拦截器,这里以一个布尔值为例子,随便一写:

public class Interceptor
{
public Object Call(String methodName, MulticastDelegate methodDelegate, params Object[] args)
{
Object obj = null;
try
{
Console.WriteLine("进入拦截器,执行之前方法"); obj = methodDelegate.Method.Invoke(methodDelegate.Target, args);
if ((bool)obj)
{
Console.WriteLine("返回真");
}
else
{
Console.WriteLine("返回假");
} Console.WriteLine("执行之后方法,离开拦截器");
}
catch (ApplicationException ex)
{
Console.WriteLine("出现异常");
} return obj;
}
}

即,在主函数里通过一个“框架API”调用这个类的代理子类来执行拦截器里的方法,DynamicProxyBuilder类代码如下:
using ConsoleApplication1;
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace Aop
{
public static class DynamicProxyBuilder
{
private const string dllName = "DynamicProxy.dll";
public static Object Wrap(Type type)
{
Type newType = null;
try
{
Type m_Type = type;
AppDomain domain = AppDomain.CurrentDomain;
AssemblyBuilder m_Assembly = domain.DefineDynamicAssembly(new AssemblyName("DynamicModule"), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder m_Module = m_Assembly.DefineDynamicModule("Module", dllName);
TypeBuilder m_TypeBuilder = m_Module.DefineType(m_Type.Name + "_proxy_" + m_Type.GetHashCode().ToString(), TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, m_Type);
MethodInfo[] methodInfos = m_Type.GetMethods();
TypeBuilder[] m_NestedTypeBuilders = new TypeBuilder[methodInfos.Length];
ConstructorBuilder[] m_NestedTypeConstructors = new ConstructorBuilder[methodInfos.Length];
FieldBuilder m_Interceptor = m_TypeBuilder.DefineField("__Interceptor", typeof(Interceptor), FieldAttributes.Private);
FieldBuilder[] m_MultiCastDelegates = new FieldBuilder[methodInfos.Length];
MethodBuilder[] m_CallBackMethods = new MethodBuilder[methodInfos.Length];
ConstructorBuilder m_ConstructorBuilder = m_TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(Interceptor) });
for (Int32 i = 0; i < m_NestedTypeBuilders.Length; i++)
{
m_NestedTypeBuilders[i] = m_TypeBuilder.DefineNestedType("__" + methodInfos[i].Name + "__delegate", TypeAttributes.NestedPrivate | TypeAttributes.Sealed, typeof(MulticastDelegate));
m_NestedTypeConstructors[i] = m_NestedTypeBuilders[i].DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(Object), typeof(IntPtr) });
m_NestedTypeConstructors[i].SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
Type[] argsType = GetParameterTypes(methodInfos[i]);
MethodBuilder mb = m_NestedTypeBuilders[i].DefineMethod("Invoke", MethodAttributes.Public, CallingConventions.Standard, methodInfos[i].ReturnType, argsType);
mb.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
}
for (Int32 i = 0; i < methodInfos.Length; i++)
{
m_MultiCastDelegates[i] = m_TypeBuilder.DefineField(methodInfos[i].Name + "_field", m_NestedTypeBuilders[i], FieldAttributes.Private);
}
for (Int32 i = 0; i < methodInfos.Length; i++)
{
Type[] argTypes = GetParameterTypes(methodInfos[i]);
m_CallBackMethods[i] = m_TypeBuilder.DefineMethod("callback_" + methodInfos[i].Name, MethodAttributes.Private, CallingConventions.Standard, methodInfos[i].ReturnType, argTypes);
ILGenerator ilGenerator = m_CallBackMethods[i].GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
for (Int32 j = 0; j < argTypes.Length; j++)
{
ilGenerator.Emit(OpCodes.Ldarg, j + 1);
}
ilGenerator.Emit(OpCodes.Call, methodInfos[i]);
ilGenerator.Emit(OpCodes.Ret);
}
for (Int32 i = 0; i < methodInfos.Length; i++)
{
Type[] argTypes = GetParameterTypes(methodInfos[i]);
MethodBuilder mb = m_TypeBuilder.DefineMethod(methodInfos[i].Name, MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard, methodInfos[i].ReturnType, argTypes);
ILGenerator ilGenerator = mb.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, m_Interceptor);
ilGenerator.Emit(OpCodes.Ldstr, methodInfos[i].Name);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, m_MultiCastDelegates[i]);
LocalBuilder local = ilGenerator.DeclareLocal(typeof(Object[]));
ilGenerator.Emit(OpCodes.Ldc_I4, argTypes.Length);
ilGenerator.Emit(OpCodes.Newarr, typeof(Object));
ilGenerator.Emit(OpCodes.Stloc, local);
ilGenerator.Emit(OpCodes.Ldloc, local);
for (Int32 j = 0; j < argTypes.Length; j++)
{
ilGenerator.Emit(OpCodes.Ldc_I4, j);
ilGenerator.Emit(OpCodes.Ldarg, j + 1);
ilGenerator.Emit(OpCodes.Box, argTypes[j]);
ilGenerator.Emit(OpCodes.Stelem_Ref);
ilGenerator.Emit(OpCodes.Ldloc, local);
}
ilGenerator.Emit(OpCodes.Call, typeof(Interceptor).GetMethod("Call", new Type[] { typeof(String), typeof(MulticastDelegate), typeof(Object[]) }));
if (methodInfos[i].ReturnType.Equals(typeof(void)))
{
ilGenerator.Emit(OpCodes.Pop);
}
else
{
ilGenerator.Emit(OpCodes.Unbox_Any, methodInfos[i].ReturnType);
}
ilGenerator.Emit(OpCodes.Ret);
}
ILGenerator ilGenerator2 = m_ConstructorBuilder.GetILGenerator();
ilGenerator2.Emit(OpCodes.Ldarg_0);
ilGenerator2.Emit(OpCodes.Call, m_Type.GetConstructor(new Type[] { }));
ilGenerator2.Emit(OpCodes.Ldarg_0);
ilGenerator2.Emit(OpCodes.Ldarg_1);
ilGenerator2.Emit(OpCodes.Stfld, m_Interceptor);
for (Int32 i = 0; i < m_MultiCastDelegates.Length; i++)
{
ilGenerator2.Emit(OpCodes.Ldarg_0);
ilGenerator2.Emit(OpCodes.Ldarg_0);
ilGenerator2.Emit(OpCodes.Ldftn, m_CallBackMethods[i]);
ilGenerator2.Emit(OpCodes.Newobj, m_NestedTypeConstructors[i]);
ilGenerator2.Emit(OpCodes.Stfld, m_MultiCastDelegates[i]);
}
ilGenerator2.Emit(OpCodes.Ret);
newType = m_TypeBuilder.CreateType();
foreach (TypeBuilder tb in m_NestedTypeBuilders)
{
tb.CreateType();
}
m_Assembly.Save(dllName);
}
catch (Exception err)
{
throw err;
}
return Activator.CreateInstance(newType, new Interceptor());
}
internal static Type[] GetParameterTypes(MethodInfo methodInfo)
{
ParameterInfo[] args = methodInfo.GetParameters();
Type[] argsType = new Type[args.Length];
for (Int32 j = 0; j < args.Length; j++)
{
argsType[j] = args[j].ParameterType;
}
return argsType;
}
}
}
这个程序在运行时会在bin下创建一个DynamicProxy.dll,里面是用Emit反射生成的代理子类,复写了父类的方法。
上面的代码里有一个Interceptor类,封装AOP框架的一个思路就是把这个类提出一个接口,里面有之前、之后、异常等方法,然后让一个抽象类实现这个接口,提供空实现骨架(模板方法模式),把这个抽象类注入到子类构造器当中来构造子类。
如果要结合项目造轮子的话,则允许以这个接口为标准二次开发具体的拦截器,并且可以根据需求封装配置界面,来配置针对系统当中哪一个具体操作命令来进行拦截。
DynamicProxyBuilder.Wrap这个方法可以封装为一个人性化的框架接口(作为AOP框架的API)来创建代理子类。
有必要将拦截器类放入IoC容器当中以防每次反射。
最后,动态代理性能很差,至少第一次生成dll很慢,而且看不懂!
真不想用框架、要自己写AOP的话,还是直接让最终执行核心方法的类实现拦截器接口,然后直接在自己的框架里调接口吧,这样还看得懂,别搞什么Emit!
最后引用马老师的一句经典语录——搞毛飞机啊!
C#利用Emit反射实现AOP,以及平台化框架封装思路的更多相关文章
- 不使用BeanUtils,利用Java反射机制:表单数据自动封装到JavaBean
在百度搜“java反射 将表单数据自动封装到javabean ”,第一页显示的都是一样的代码,都是利用导入第三方jar包<commons-beanutils>和<commons-lo ...
- C# 使用Emit实现动态AOP框架 (一)
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- linux下利用elk+redis 搭建日志分析平台教程
linux下利用elk+redis 搭建日志分析平台教程 http://www.alliedjeep.com/18084.htm elk 日志分析+redis数据库可以创建一个不错的日志分析平台了 ...
- 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...
- 利用R语言打造量化分析平台
利用R语言打造量化分析平台 具体利用quantmod包实现对股票的量化分析 1.#1.API读取在线行情2.#加载quantmod包3.if(!require(quantmod)){4. instal ...
- cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程)
链接地址:http://www.cocoachina.com/bbs/read.php?tid=333937 cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程 ...
- 利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils
有时遇到将数据传输对象转换成JSON串会将属性值为空的属性去掉,利用Java反射实现JavaBean对象数据传输对象的相同属性复制并初始化数据传输对象属性为空的属性,然后转换成JSON串 packag ...
- 利用基于@AspectJ的AOP实现权限控制
一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...
- 利用JAVA反射机制设计通用的DAO
利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...
随机推荐
- Mediator - 中介者模式
定义 用一个中介对象来封装一系列的对象的交互.中介者使各对象不须要显示地相互使用,从而使其耦合松散,并且能够独立的改变他们之间的交互. 案例 比方有一个图像界面,在界面上有一个输入框LineEdit, ...
- SQL2005性能分析一些细节功能你是否有用到?
原文:SQL2005性能分析一些细节功能你是否有用到? 我相信很多朋友对现在越来越大的数据量而感到苦恼,可是总要面对现实啊,包括本人在内的数据库菜鸟们在开发B/S程序时,往往只会关心自己的数据是否正确 ...
- Dialog中显示倒计时,到时自己主动关闭
这里直接用系统Dialog中加入了倒计时的显示,假设用自己定义Dialog会更美观: private TextView mOffTextView; private Handler mOffHandle ...
- CentOs Linux 文件位置标记
vsFTP默认位置: 匿名:/var/ftp/ 用户:/home/用户名 配置文件:/etc/vsftpd/ (一般安装软件后都会在/etc/下生成一个软件相关的配置文件夹) 防火墙位置: /etc/ ...
- Humming Bird A20 SPI2驱动编译
Humming Bird A20 SPI2使用编译 Yao.GUET 2014-07-17,请注明出处:http://blog.csdn.net/Yao_GUET A20上带有4个spi接口,因为Hu ...
- HTML5 五彩圆环Loading加载动画实现教程
原文:HTML5 五彩圆环Loading加载动画实现教程 今天我们要来介绍一款效果很特别的HTML5 Loading加载动画,不像其他的Loading动画,这款Loading动画颜色很丰富,并且在转圈 ...
- node.js + mongodb
node.js + mongodb 这次内容是结合bootstrap把登陆注册做好,还有就是express的中间件等问题. 看这篇博客之前建议先看我上篇写的那篇博客http://www.cnblogs ...
- [译]Java 设计模式之抽象工厂
(文章翻译自Java Design Pattern: Abstract Factory) 抽象工厂模式针对工厂模式增加了抽象层.如果我们使用抽象工厂模式和工厂模式比较的话,很明显抽象工厂模式增加了一个 ...
- Entity Framework 丢失数据链接的绑定,在已绑好的EDMX中提示“Choose Your Data Connection”
早先做的一个练手的项目中, 使用到了Entity framework . 最近碰到一个问题,在edmx 里面选择“Update model from Database” 的时候提示了 “Choose ...
- 网易ios 面试
1 说说 你对 MRC和 ARC 的理解 2 对OC内存分析 有什么好的方法, 3 corePlot 4 pop 动画 5 cocoapods 6 GCD 7 瀑布流 及 uicollection ...