您的位置:首页 > 编程语言

动态代理示例(根据博客园BillGan代码增加注释和辅助阅读类)

2010-01-02 15:38 351 查看
看了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;

示例代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: