动态代理示例(根据博客园BillGan代码增加注释和辅助阅读类)
看了http://www.cnblogs.com/BillGan/archive/2009/12/18/1627112.html?login=1#commentform关于动态代理的示例,觉得理解上有困难,于是根据对示例代码的理解写了一个人工代理实现类和与之对应的Emit动态生成类(从原示例修改),有了这两个类代码的对照,阅读理解都比较容易:
1.人工编写产生代理类(实际中肯定不这样做,本例只是说明动态代理的实现原理)
/// <summary>
/// 人工产生动态的代理类,和类CTypeBuilder通过Emit产生的代理类是一样的
/// 编写本类的目的是帮助理解Emit代码
/// </summary>
public class CProxy_Class : IClass1
{
/// <summary>
/// 被代理对象
/// </summary>
private Object sourceObj;
/// <summary>
/// 拦截器
/// </summary>
private IStandardIntercept intercept;
/// <summary>
/// 创建代理
/// </summary>
/// <param name="targetobj">被代理对象</param>
/// <param name="intercept">拦截器</param>
public CProxy_Class(Object targetobj, IStandardIntercept intercept)
{
this.sourceObj = targetobj;
this.intercept = intercept;
}
/// <summary>
/// 实现接口方法
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public virtual void test(Guid a, Int32 b)
{
MethodInfo mi;//loc0
Object[] oa;//loc1
Invocation inv;//loc2
Type[] ta;//loc3
Type t;//loc4
//获取sourceObj中的当前MethodInfo并存入loc4中
t = sourceObj.GetType();
//获取参数类型数组
ta=new Type[2];
ta[0] = a.GetType();
ta[1] = b.GetType();
mi=t.GetMethod("test", ta);
oa=new Object[2];//参数个数固定为2
oa[0] = a;
oa[1] = b;
inv = new Invocation();
inv.Method = mi;
inv.Proxy = sourceObj;
inv.Arguments = oa;
inv.TargetType = sourceObj.GetType();
intercept.PreProceed(inv);
intercept.Proceed(inv);
intercept.PostProceed(inv);
}
}
2.Emit方式产生动态代理类
public class CTypeBuilder
{
/// <summary>
/// 动态根据被代理对象和拦截器生成代理类实例,本Emit代码和CProxy_Class对应,阅读时请参考CProxy_Class阅读
/// </summary>
/// <typeparam name="T">生成的代理类类型</typeparam>
/// <param name="targetObject">被代理对象(目标对象)</param>
/// <param name="intercept">拦截器</param>
/// <returns>代理类实例/T类型的实例</returns>
public static T Create<T>(T targetObject, IStandardIntercept intercept)
{
Type targetType = typeof(T);
//获取当前AppDomain
AppDomain currentAppDomain = AppDomain.CurrentDomain;
//System.Reflection.AssemblyName 是用来表示一个Assembly的完整名称的
AssemblyName assyName = new AssemblyName();
//为要创建的Assembly定义一个名称(这里忽略版本号,Culture等信息)
assyName.Name = "MyAssemblyFor_" + targetType.Name;
Version vv = new Version(1, 0, 0, 2);
assyName.Version = vv;
//获取AssemblyBuilder
//AssemblyBuilderAccess有Run,Save,RunAndSave三个取值
AssemblyBuilder assyBuilder = currentAppDomain.DefineDynamicAssembly(assyName, AssemblyBuilderAccess.RunAndSave);
//获取ModuleBuilder,提供String参数作为Module名称,随便设一个
ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule("MyModuleFor_" + targetType.Name);
//新类型的名称:随便定一个
String newTypeName = "Proxy_" + targetType.Name;
//新类型的属性:要创建的是Class,而非Interface,Abstract Class等,而且是Public的
TypeAttributes newTypeAttribute = TypeAttributes.Class | TypeAttributes.Public;
//声明要创建的新类型的父类型
Type newTypeParent;
//声明要创建的新类型要实现的接口
Type[] newTypeInterfaces;
//对于基类型是否为接口,作不同处理
if (targetType.IsInterface)
{
newTypeParent = null;
newTypeInterfaces = new Type[] { targetType };
}
else
{
newTypeParent = targetType;
newTypeInterfaces = new Type[0];
}
//得到类型生成器
TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName, newTypeAttribute, newTypeParent, newTypeInterfaces);
//定义字段
FieldBuilder fbuilder_obj = typeBuilder.DefineField("sourceObj", typeof(Object), FieldAttributes.Private);
FieldBuilder fbuilder_intercept = typeBuilder.DefineField("intercept", typeof(IStandardIntercept), FieldAttributes.Private);
#region 创建构造函数
//public CProxy_Class(Object targetobj, IStandardIntercept intercept)
ConstructorBuilder conBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(Object), typeof(IStandardIntercept) });
ILGenerator conIlGen = conBuilder.GetILGenerator();
//this.sourceObj = targetobj;
conIlGen.Emit(OpCodes.Ldarg_0);
conIlGen.Emit(OpCodes.Ldarg_1);
conIlGen.Emit(OpCodes.Stfld, fbuilder_obj);
//this.intercept = intercept;
conIlGen.Emit(OpCodes.Ldarg_0);
conIlGen.Emit(OpCodes.Ldarg_2);
conIlGen.Emit(OpCodes.Stfld, fbuilder_intercept);
conIlGen.Emit(OpCodes.Ret);
#endregion
//以下将为新类型声明方法:新类型应该override基类型的所有virtual方法
//得到基类型的所有方法
MethodInfo[] targetMethods = targetType.GetMethods();
//遍历各个方法,对于Virtual的方法,获取其签名,作为新类型的方法
foreach (MethodInfo targetMethod in targetMethods)
{
//只挑出virtual的方法
if (!targetMethod.IsVirtual)
{
continue;
}
//得到方法的各个参数的类型
ParameterInfo[] paramInfo = targetMethod.GetParameters();
int paramCount = paramInfo.Length;
Type[] paramType = new Type[paramInfo.Length];
for (int i = 0; i < paramInfo.Length; i++)
{
paramType[i] = paramInfo[i].ParameterType;
}
//传入方法签名,得到方法生成器
//实现需要实现的方法.方法的实现就在这里
MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, targetMethod.ReturnType, paramType);
MethodInfo getTypeMI = typeof(object).GetMethod("GetType", new Type[] { });
MethodInfo getMethodMI = typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string), typeof(Type[]) });
//由于要生成的是具体类,所以方法的实现是必不可少的。而方法的实现是通过Emit IL代码来产生的
//得到IL生成器
ILGenerator ilGen = methodBuilder.GetILGenerator();
//定义局部变量
//MethodInfo mi;//loc0
//Object[] oa;//loc1
//Invocation inv;//loc2
//Type[] ta;//loc3
//Type t;//loc4
ilGen.DeclareLocal(typeof(MethodInfo), true); //loc0
ilGen.DeclareLocal(typeof(object[]), true);//loc1
ilGen.DeclareLocal(typeof(Invocation), true);//loc2
ilGen.DeclareLocal(typeof(Type[]), true);//loc3,参数数组
ilGen.DeclareLocal(typeof(Type), true);//loc4
//获取sourceObj中的当前type信息并存入loc4中
//t = sourceObj.GetType();
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_obj);
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stloc, 4);
//获取参数类型数组
//ta = new Type[2];//我在类CProxy_Class中把参数个数paramCount简单的固定为2
ilGen.Emit(OpCodes.Ldc_I4, paramCount);//对于本示例,test方法有两个参数,所以paramCount=2
ilGen.Emit(OpCodes.Newarr, typeof(Type));
ilGen.Emit(OpCodes.Stloc_3);
//循环把所有参数类型放在loc3中,以下的循环实现如下两条语句
//ta[0] = a.GetType();
//ta[1] = b.GetType();
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldloc_3);
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stelem_Ref);
}
//mi=t.GetMethod("test", ta);
ilGen.Emit(OpCodes.Ldloc, 4);
ilGen.Emit(OpCodes.Ldstr, targetMethod.Name);
ilGen.Emit(OpCodes.Ldloc_3);
ilGen.EmitCall(OpCodes.Call, getMethodMI, null);
ilGen.Emit(OpCodes.Stloc_0);
//获取参数并将其存入object[]类型变量loc1中
//oa=new Object[2];
ilGen.Emit(OpCodes.Ldc_I4, paramCount);
ilGen.Emit(OpCodes.Newarr, typeof(object));
ilGen.Emit(OpCodes.Stloc_1);
//以下循环实现如下两条语句
//oa[0] = a;
//oa[1] = b;
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldloc_1);
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.Emit(OpCodes.Stelem_Ref);
}
//创建Invocation对象
//inv = new Invocation();
ConstructorInfo InvocationCI = typeof(Invocation).GetConstructor(Type.EmptyTypes);
ilGen.Emit(OpCodes.Newobj, InvocationCI);
ilGen.Emit(OpCodes.Stloc_2);
//给Method值
//inv.Method = mi;拦截器中就是调用该方法
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldloc_0);
ilGen.EmitCall(OpCodes.Call, typeof(Invocation).GetMethod("set_Method", new Type[] { typeof(MethodInfo) }), null);
//给Target值
//inv.Proxy = sourceObj;//拦截器中拦截调用对象
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_obj);
ilGen.EmitCall(OpCodes.Call, typeof(Invocation).GetMethod("set_Proxy", new Type[] { typeof(Object) }), null);
//给Arguments值,这个也可以不赋值,由METHOD可以获取到
//inv.Arguments = oa;
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldloc_1);
ilGen.EmitCall(OpCodes.Call, typeof(Invocation).GetMethod("set_Arguments", new Type[] { typeof(Object[]) }), null);
//给TargetType赋值
//inv.TargetType = sourceObj.GetType();
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_obj);
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.EmitCall(OpCodes.Call, typeof(Invocation).GetMethod("set_TargetType", new Type[] { typeof(Type) }), null);
//调用拦截器拦截前方法
//intercept.PreProceed(inv);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_intercept);
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Call, intercept.GetType().GetMethod("PreProceed", new Type[] { typeof(Invocation) }));
//调用自身,改为拦截器的方法后就可以控制方法本身了。
//ilGen.Emit(OpCodes.Ldarg_0);
//for (var i = 1; i <= paramInfo.Length;i++ )
// ilGen.Emit(OpCodes.Ldarg,i);
//ilGen.Emit(OpCodes.Call,targetMethod);
//调用
//intercept.Proceed(inv);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_intercept);
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Call, intercept.GetType().GetMethod("Proceed", new Type[] { typeof(Invocation) }));
//调用拦截器拦截后方法
//intercept.PostProceed(inv);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder_intercept);
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Call, intercept.GetType().GetMethod("PostProceed", new Type[] { typeof(Invocation) }));
ilGen.Emit(OpCodes.Ret);
}
assyBuilder.Save("CTB.dll");//保存为DLL程序集
Type rt = typeBuilder.CreateType();//创建代理类类型
return (T)Activator.CreateInstance(rt, new object[] { targetObject, intercept });//根据动态产生的代理类类型创建实例并返回
}
}
使用方法:
IClass1 c1=CTypeBuilder.Create<IClass1>(new Class1(), new UserIntercept());
if (c1 != null)
{
c1.test(Guid.NewGuid(), 120);
}
c1 = null;
IClass1 xx = new CProxy_Class(new Class1(), new UserIntercept());
xx.test(Guid.NewGuid(), 110);
xx = null;
示例代码下载