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,以及平台化框架封装思路的更多相关文章

  1. 不使用BeanUtils,利用Java反射机制:表单数据自动封装到JavaBean

    在百度搜“java反射 将表单数据自动封装到javabean ”,第一页显示的都是一样的代码,都是利用导入第三方jar包<commons-beanutils>和<commons-lo ...

  2. C# 使用Emit实现动态AOP框架 (一)

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

  3. linux下利用elk+redis 搭建日志分析平台教程

    linux下利用elk+redis 搭建日志分析平台教程 http://www.alliedjeep.com/18084.htm   elk 日志分析+redis数据库可以创建一个不错的日志分析平台了 ...

  4. 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换

    作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...

  5. 利用R语言打造量化分析平台

    利用R语言打造量化分析平台 具体利用quantmod包实现对股票的量化分析 1.#1.API读取在线行情2.#加载quantmod包3.if(!require(quantmod)){4. instal ...

  6. cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程)

    链接地址:http://www.cocoachina.com/bbs/read.php?tid=333937 cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程 ...

  7. 利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils

    有时遇到将数据传输对象转换成JSON串会将属性值为空的属性去掉,利用Java反射实现JavaBean对象数据传输对象的相同属性复制并初始化数据传输对象属性为空的属性,然后转换成JSON串 packag ...

  8. 利用基于@AspectJ的AOP实现权限控制

    一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...

  9. 利用JAVA反射机制设计通用的DAO

    利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,    那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...

随机推荐

  1. 屏蔽webbrowser控件右键的一种方法

    原文:屏蔽webbrowser控件右键的一种方法 Option ExplicitPrivate Declare Sub ZeroMemory Lib "KERNEL32" Alia ...

  2. Zepto

    移动开发流量省起来之Zepto 事情是这样的:最近开发的一个手机网站客户反应访问起来特别慢,刷了半天才能看到页面,然后问我们是不是网站出问题了.于是我赶紧找了各种手机测试一下,没有问题,首先排除程序错 ...

  3. 如何将经纬度利用Google Map API显示C# VS2005 Sample Code

    原文 如何将经纬度利用Google Map API显示C# VS2005 Sample Code 日前写了一篇如何用GPS抓取目前所在,并回传至资料库储存,这篇将会利用这些回报的资料,将它显示在地图上 ...

  4. C# 获取磁盘容量

    原文:C# 获取磁盘容量 /// 获取指定驱动器的空间总大小(单位为B) /// </summary> /// <param name="str_HardDiskName& ...

  5. android studio 添加到项目库中的项目

    工程-对-new module-Android Library-module name和package name 它应该在同一个库被引入. 然后在该文件夹replace新的library 在gradl ...

  6. 2014Esri国际用户大会ArcGIS Online

    1.基于什么是新的ArcGISOnline? ArcGISOnline不断更新.大约每四个月就会把新的增强的功能公布到各部分中.有新的空间分析的应用程序,如 Explorer forArcGIS,ap ...

  7. C#验证IP地址

    using System.Net; try { IPAddress a = IPAddress.Parse(输入的IP字符串); } catch (System.Exception ex) { Mes ...

  8. linux下C语言中的flock函数使用方法 .

    表头文件  #include<sys/file.h> 定义函数  int flock(int fd,int operation); 函数说明  flock()会依參数operation所指 ...

  9. Android接口测试-JUnit入门

    1.下载:http://www.junit.org 2.配置AndroidManifest.xml,在application节点加入 <!--使用单元测试库-->        <u ...

  10. 6. SQL Server数据库监控 - 如何告警

    原文:6. SQL Server数据库监控 - 如何告警 常用的告警方式大致有:短信.邮件.应用程序 (beep提示,图标提示,升窗提示等),可是不能一直坐在电脑前看着应用程序,或者用脚本部署监控,根 ...