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. 房间计费系统改造E-R图纸设计

    简单的学习过程:     这几天忙得太混乱了,用了近一个星期才设计好.我在这段时间遇到的困难,就积极找师哥师姐指点迷津,如今多少总算是有些拿得出手的成果. 学习成果: Entity Relations ...

  2. C#实现对mongoDB的简单增删查改

    首先添加所需要驱动包(可通过nuget获得) using MongoDB.Bson;using MongoDB.Driver;using MongoDB.Driver.Builders; 一.设置配置 ...

  3. Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试

    Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试   需要FQ才能安装,使用时应该不用FQ了,除非使用postman的历史记录功能:   非常棒的C ...

  4. Django教程汇总

    Django基础教程 被解放的姜戈01 初试天涯 被解放的姜戈02 庄园疑云 被解放的姜戈03 所谓伊人 被解放的姜戈04 各取所需 被解放的姜戈05 黑面管家 被解放的姜戈06 假作真时 Djang ...

  5. orleans开篇之hello world

    orleans开篇之hello world 什么是orleans Orleans是一个建立在.NET之上的,设计的目标是为了方便程序员开发需要大规模扩展的云服务.Orleans项目基本上被认为是并行计 ...

  6. Java遍历解析URL类型字符串中参数

    public static void main(String[] args) { String str="&emailCheckURL=447&useremail=vip@c ...

  7. APP-随身听

    简单到复杂听你的专属音响界,听金融.听物业,听新闻和其他节目专辑,简要介绍了新的音频应用,给你不一样的聆听体验.还记得老歌做?这里有.您留声机的一部分!很简单的音频应用,随时随地与此应用程序来听你的私 ...

  8. 编程算法 - 二叉树的深度 代码(C)

    二叉树的深度 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入一棵二叉树的根节点, 求该树的深度. 依次选择最深的左右子树, 然后递归加1. ...

  9. [翻译]如何编写GIMP插件(二)

    写在前面: 本人翻译并不专业,甚至英语不好,翻译内容仅供参考.由于博主是边学边翻译,所以不能保证翻译的准确性和正确性,如果可以,请查看原版学习,本文仅作学习记录之用. <How to write ...

  10. Java中间Map List Set和其他收藏品

    Map List Set和其他收藏品: 一.概述 在JAVA的util包中有两个全部集合的父接口Collection和Map,它们的父子关系: +Collection 这个接口extends自 --j ...