zoukankan      html  css  js  c++  java
  • 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类代码如下:

     View Code

    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!

      最后引用马老师的一句经典语录——搞毛飞机啊!

     
     
  • 相关阅读:
    深入浅出ES6(十二):代理 Proxies
    深入浅出ES6(十一):生成器 Generators,续篇
    深入浅出ES6(十):集合
    深入浅出ES6(九):学习Babel和Broccoli,马上就用ES6
    深入浅出ES6(八):Symbols
    根据后端返回的数据进行中文排序操作
    vue之组件(组件之间相互传参)
    mongodb用户权限增删改查
    mongodb添加文件和导出文件
    js中cookie编码解码操作
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3304986.html
Copyright © 2011-2022 走看看