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类代码如下:
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,以及平台化框架封装思路的更多相关文章
- 不使用BeanUtils,利用Java反射机制:表单数据自动封装到JavaBean
在百度搜“java反射 将表单数据自动封装到javabean ”,第一页显示的都是一样的代码,都是利用导入第三方jar包<commons-beanutils>和<commons-lo ...
- C# 使用Emit实现动态AOP框架 (一)
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- linux下利用elk+redis 搭建日志分析平台教程
linux下利用elk+redis 搭建日志分析平台教程 http://www.alliedjeep.com/18084.htm elk 日志分析+redis数据库可以创建一个不错的日志分析平台了 ...
- 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...
- 利用R语言打造量化分析平台
利用R语言打造量化分析平台 具体利用quantmod包实现对股票的量化分析 1.#1.API读取在线行情2.#加载quantmod包3.if(!require(quantmod)){4. instal ...
- cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程)
链接地址:http://www.cocoachina.com/bbs/read.php?tid=333937 cocos2d-x3.9利用cocos引擎一键打包Android平台APK(C++小白教程 ...
- 利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils
有时遇到将数据传输对象转换成JSON串会将属性值为空的属性去掉,利用Java反射实现JavaBean对象数据传输对象的相同属性复制并初始化数据传输对象属性为空的属性,然后转换成JSON串 packag ...
- 利用基于@AspectJ的AOP实现权限控制
一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...
- 利用JAVA反射机制设计通用的DAO
利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...
随机推荐
- 一款非常棒的纯CSS3 3D菜单演示及制作教程
原文:一款非常棒的纯CSS3 3D菜单演示及制作教程 这段时间比较忙,很久没在这里分享一些漂亮的HTML5和CSS3资源了,今天起的早,看到一款很不错的CSS3 3D菜单,觉得非常上眼,就将它分享给大 ...
- 【高德地图API】从零开始学高德JS API(八)——地址解析与逆地址解析
原文:[高德地图API]从零开始学高德JS API(八)——地址解析与逆地址解析 摘要:无论是百度LBS开放平台,还是高德LBS开放平台,其调用量最高的接口,必然是定位,其次就是地址解析了,又称为地理 ...
- 【百度地图API】如何根据摩卡托坐标进行POI查询,和计算两点距离
原文:[百度地图API]如何根据摩卡托坐标进行POI查询,和计算两点距离 摘要: 百度地图API有两种坐标系,一种是百度经纬度,一种是摩卡托坐标系.在本章你将学会: 1.如何相互转换这两种坐标: 2. ...
- 利用EntityFramework获得双色球数据库
原文 利用EntityFramework获得双色球数据库 双色球想必大家都很熟悉了,尽管屡买屡不中,但还是会买.以前就想过利用双色球的走势图得到双色球的数据库,至于得到数据库干什么倒没想过,不过对以往 ...
- 理解iOS软件开发框架
iOS软件开发框架理解 这个东西是硬伤,框架?自带的mvc? 自带的UIViewController UIView UINavigationController 这些算不算?当然算的,cocoa框架嘛 ...
- 完整的thinphp+phpexcel实现excel报表的输出(有图有效果)
准备工作:1.下载phpexcel1.7.6类包:2.解压至TP框架的ThinkPHP\Vendor目录下,改类包文件夹名为PHPExcel176,目录结构如下图: 编写代码(以一个订单汇 ...
- 来选择一款适合你网站的CMS建站程序吧
1:首页我们要搞清楚什么叫cms? ContentManagementSystem就是cms的全名,意思就是内容管理系统.cms整站系统是以文章系统为核心,增加用户需要的模块,如文章.图片.下载等,提 ...
- 快速构建Windows 8风格应用3-打包发布应用
原文:快速构建Windows 8风格应用3-打包发布应用 本篇博文主要介绍如何打包应用程序,成功后如何部署应用程序,最后介绍如何发布应用程序到应用商店中. 如何打包Windows 8风格应用程序呢? ...
- 微软宣布.NET开发环境将开源 支持Mac OS X和Linux
微软宣布.NET开发环境将开源 支持Mac OS X和Linux 投递人 itwriter 发布于 2014-11-13 06:58 评论(55) 有4388人阅读 原文链接 [收藏] « » ...
- Ubuntu12.04环境搭建遇到的问题和建议(一个)
后的新公司需要在Ubuntu12.04在结构Android开发环境,在这个过程中,我们还是会遇到很多问题,这里记录.为了方便自己的未来,有人谁需要参考.从网络! 1. Q:在终端: sudo apt- ...