• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

peter-pc

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

动态代理示例(根据博客园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;


示例代码下载

 

 

 

 

 

posted on 2010-01-02 15:38  peter-pc  阅读(294)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3