目  录

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

C# 使用Emit实现动态AOP框架 (二)

C# 使用Emit实现动态AOP框架 (三)

C# 使用Emit实现动态AOP框架 进阶篇之异常处理

C# 使用Emit实现动态AOP框架 进阶篇之优化

准备工作完成后,DynamicProxy类就可以开始了。

创建代理对象 Create

创建代理对象主要分为五步:

(1)、获取被代理类型构造函数参数列表

   Type[] parameterTypes = parameters == null ? Type.EmptyTypes : parameters.Select(p => p.GetType()).ToArray();

 (2)、根据构造函数参数列表创建代理类型
    Type proxyType = CreateProxyType(srcType, parameterTypes);

 (3)、使用动态方法生成创建代理类型实例的委托
    CreateFunc<T>(proxyType, parameterTypes)

 (4)、生成ProxyType对象,存入代理类型字典,以备二次调用
     obj = new ProxyType<T>(srcType.FullName, signature, CreateFunc<T>(proxyType, parameterTypes));

     func_Dictionary.Add(srcType.FullName + "(" + signature + ")", obj);

(5)、通过委托生成代理对象
     Func<object[], T> func = (obj as ProxyType<T>).CreateFunc;

      if (func == null)
throw new Exception("unknown exception"); return func(parameters);
         /// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}

1.1、根据构造函数参数列表创建代理类型 CreateProxyType

(1)、通过Emit生成动态程序集、动态模块以及动态类型

XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
        (srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes);

(2)、重写被切入的属性

OverrideProperty(bc.DynamicTypeBuilder, propertyInfo);

(3)、重写被切入的方法

OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);

(4)、生成代理类型

Type result = bc.DynamicTypeBuilder.CreateType();

         /// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}

1.1.1 重写被切入的属性 OverrideProperty

        /// <summary>
/// 重写被代理类的属性
/// </summary>
/// <param name="dynamicTypeBuilder"></param>
/// <param name="info">属性信息</param>
/// <param name="rangeType">切面范围</param>
/// <param name="onEntryExit">切面公共调用方法</param>
private static void OverrideProperty(TypeBuilder dynamicTypeBuilder, PropertyInfo info)
{
//不需要切入直接返回
object[] aspectAttributes = info.GetCustomAttributes(typeof(AspectAttribute), false); if (aspectAttributes.Length == ) return; PropertyBuilder dynamicPropertyBuilder = dynamicTypeBuilder.DefineProperty(info.Name, PropertyAttributes.HasDefault, info.PropertyType, null); //Getter Setter 方法标识
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; MethodBuilder getter = dynamicTypeBuilder.DefineMethod("get_" + info.Name, getSetAttr, info.PropertyType, Type.EmptyTypes); ILGenerator getIL = getter.GetILGenerator(); ILGenerateProxyMethod(getIL, info.GetGetMethod(), Type.EmptyTypes, aspectAttributes); //覆盖自动生成的Getter
MethodInfo getMethod = info.GetGetMethod(); if (getMethod != null) dynamicTypeBuilder.DefineMethodOverride(getter, getMethod); //给属性设置Get、Set方法
dynamicPropertyBuilder.SetGetMethod(getter); //重写Set 方法
MethodBuilder setter = dynamicTypeBuilder.DefineMethod("set_" + info.Name, getSetAttr, typeof(void), new Type[] { info.PropertyType }); ILGenerator setIL = setter.GetILGenerator(); ILGenerateProxyMethod(setIL, info.GetSetMethod(), new Type[] { info.PropertyType }, aspectAttributes); //覆盖自动生成的Setter
MethodInfo setMethod = info.GetSetMethod(); if (setMethod != null) dynamicTypeBuilder.DefineMethodOverride(setter, setMethod); dynamicPropertyBuilder.SetSetMethod(setter);
}

1.1.2 重写被切入的方法 OverrideMethod

         /// <summary>
/// 重写被代理类的指定方法
/// </summary>
/// <param name="typeBuilder">类型</param>
/// <param name="src_Method">被代理方法</param>
/// <param name="aspectAttributes">代理特性集合</param>
private static void OverrideMethod(TypeBuilder typeBuilder, MethodInfo src_Method, object[] aspectAttributes)
{
if (aspectAttributes == null || aspectAttributes.Length == ) return; MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; //获取当前方法参数列表
Type[] paramTypes = XDynamic.GetMethodParameterTypes(src_Method); ILGenerator il = typeBuilder.DefineMethod(src_Method.Name, attr, src_Method.ReturnType, paramTypes).GetILGenerator(); ILGenerateProxyMethod(il, src_Method, paramTypes, aspectAttributes);
}

1.1.3 生成代理方法 ILGenerateProxyMethod

         /// <summary>
///
/// </summary>
/// <param name="il_ProxyMethod"></param>
/// <param name="src_Method"></param>
/// <param name="paramTypes"></param>
/// <param name="aspectAttributes"></param>
private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes)
{
int aspectCount = aspectAttributes.Length; //生成切面上下文
LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); //申明临时存放切面对象和OnExit方法的变量
var aspectLocalBuilders = new LocalBuilder[aspectCount];
var onExit_Methods = new MethodInfo[aspectCount]; //初始化标记的切面对象,并调用切面对象的OnEntry方法
for (int i = ; i < aspectCount; i++)
{
//创建一个切面对象
var aspectType = aspectAttributes[i].GetType();
var aspect = il_ProxyMethod.DeclareLocal(aspectType);
ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); il_ProxyMethod.Emit(OpCodes.Newobj, constructor);
il_ProxyMethod.Emit(OpCodes.Stloc, aspect); var onEntry_method = aspectType.GetMethod("OnEntry");
onExit_Methods[i] = aspectType.GetMethod("OnExit"); //调用BeforeInvoke
il_ProxyMethod.Emit(OpCodes.Ldloc, aspect);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method);
il_ProxyMethod.Emit(OpCodes.Nop); aspectLocalBuilders[i] = aspect;
} //类对象,参数值依次入栈
for (int i = ; i <= paramTypes.Length; i++)
il_ProxyMethod.Emit(OpCodes.Ldarg, i); //调用基类的方法
il_ProxyMethod.Emit(OpCodes.Call, src_Method); //定义返回值
LocalBuilder result = null; //如果有返回值,保存返回值到局部变量
if (src_Method.ReturnType != typeof(void))
{
result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Stloc, result); //给AspectContext的属性Result赋值
var resultSetMethod = typeof(AspectContext).GetMethod("set_Result");
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值
il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值
} //调用横切对象的OnExit方法
for (int i = ; i < aspectCount; i++)
{
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]);
il_ProxyMethod.Emit(OpCodes.Nop);
} //如果有返回值,则把返回值压栈
if (result != null)
il_ProxyMethod.Emit(OpCodes.Ldloc, result); il_ProxyMethod.Emit(OpCodes.Ret);//返回
}

1.1.4 生成切面上下文对象 CreateAspectContext

   /// <summary>
/// 生成切面上下文对象
/// </summary>
/// <param name="il"></param>
/// <param name="methodName">方法名称</param>
/// <param name="paramTypes">参数类型</param>
/// <returns></returns>
private static LocalBuilder CreateAspectContext(ILGenerator il, string methodName, Type[] paramTypes)
{
//AspectContext.ParameterArgs 类型为 object[] //声明一个类型为object的局部数组
il.DeclareLocal(typeof(object[]));
//数组长度入栈
il.Emit(OpCodes.Ldc_I4, paramTypes.Length);
//生成新数组
il.Emit(OpCodes.Newarr, typeof(object));
//赋值给局部数组变量
il.Emit(OpCodes.Stloc_0); //遍历参数,并存入数组
for (int i = ; i < paramTypes.Length; i++)
{
il.Emit(OpCodes.Ldloc_0);//数组入栈
il.Emit(OpCodes.Ldc_I4, i);//数组下标入栈
il.Emit(OpCodes.Ldarg, i + );//按下标加载对应的参数
if (paramTypes[i].IsValueType)//参数为值类型,装箱
il.Emit(OpCodes.Box, paramTypes[i]);
il.Emit(OpCodes.Stelem_Ref);//将参数存入数组
} //获取AspectContext构造函数
Type aspectContextType = typeof(AspectContext);
ConstructorInfo info = aspectContextType.GetConstructor(new Type[] { typeof(object), typeof(string), typeof(object[]) }); //生成一个AspectContext 对象
il.Emit(OpCodes.Ldarg_0);//加载调用对象
il.Emit(OpCodes.Ldstr, methodName);//加载方法名称
il.Emit(OpCodes.Ldloc_0);//加载由参数生成的局部数组变量
il.Emit(OpCodes.Newobj, info); //声明一个AspectContext局部变量
LocalBuilder aspectContext = il.DeclareLocal(aspectContextType);
il.Emit(OpCodes.Stloc, aspectContext); return aspectContext;
}

1.2 使用动态方法生成创建代理类型实例的委托

         /// <summary>
/// 生成创建代理类型实例的委托
/// </summary>
/// <typeparam name="T">被代理类型</typeparam>
/// <param name="proxyType">代理类型</param>
/// <param name="parameterTypes">代理类型构造函数参数类型</param>
/// <returns></returns>
private static Func<object[], T> CreateFunc<T>(Type proxyType, Type[] parameterTypes)
{
DynamicMethod method = new DynamicMethod(proxyType.Name + "_CF", typeof(T), new Type[] { typeof(object[]) }, true); var il = method.GetILGenerator(); //根据T类型的构造函数参数列表,依次将 object[] parameters 中对应的值加载到堆栈(并做相应类型转换),以被T类型的构造函数使用
for (int i = ; i < parameterTypes.Length; i++)
{ il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref); if (parameterTypes[i].IsValueType)
// 如果是值类型,拆箱
il.Emit(OpCodes.Unbox_Any, parameterTypes[i]);
else
// 如果是引用类型,转换
il.Emit(OpCodes.Castclass, parameterTypes[i]);
} ConstructorInfo info = proxyType.GetConstructor(parameterTypes); if (info == null) throw new Exception("代理类不存在,与指定参数列表相对应的构造函数。"); il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Ret); //建立《生成指定类型T的实例》的委托
return method.CreateDelegate(typeof(Func<object[], T>)) as Func<object[], T>;
}

1.3 ProxyType类

   public class ProxyType<T>
{
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name">类型名称</param>
/// <param name="parameterSignature">构造函数参数签名</param>
/// <param name="createFunc">创建被代理类型实例的委托</param>
public ProxyType(string name, string parameterSignature, Func<object[], T> createFunc)
{
Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc;
}
#endregion #region 属性 /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 参数类型签名
/// </summary>
public string ParameterSignature { get; set; } /// <summary>
/// 创建被代理类型实例的委托
/// </summary>
public Func<object[], T> CreateFunc { get; set; } #endregion
}

到此为止一个简单的Aop框架就完成了。下一篇会介绍一个下BuilderCollection类

C# 使用Emit实现动态AOP框架 (三)的更多相关文章

  1. C# 使用Emit实现动态AOP框架 (二)

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

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

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

  3. C# 使用Emit实现动态AOP框架 进阶篇之异常处理

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

  4. C# 使用Emit实现动态AOP框架 进阶篇之优化

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

  5. .NET 下基于动态代理的 AOP 框架实现揭秘

    .NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...

  6. C#利用Emit反射实现AOP,以及平台化框架封装思路

    C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...

  7. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  8. JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架

    1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...

  9. Dora.Interception,为.NET Core度身打造的AOP框架:全新的版本

    Dora.Interception 1.0(Github地址:可以访问GitHub地址:https://github.com/jiangjinnan/Dora)推出有一段时间了,最近花了点时间将它升级 ...

随机推荐

  1. Node.js中npm常用命令大全

    npm是什么 NPM的全称是Node Package Manager,是随同NodeJS一起安装的包管理和分发工具,它很方便让JavaScript开发者下载.安装.上传以及管理已经安装的包. npm ...

  2. 黑马vue---31-32、vue过滤器实例

    黑马vue---31-32.vue过滤器实例 一.总结 一句话总结: vue内部的东西,无论是过滤器还是组件,都是键值对的方式 1.过滤器的定义语法? Vue.filter('过滤器的名称', fun ...

  3. Flume-自定义 Sink

    Sink 不断地轮询 Channel 中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统.或者被发送到另一个 Flume Agent. Sink 是完全事务性的. 在从 Channel 批 ...

  4. Python 类中__init__()方法中的形参与如何修改类中属性的值

    一.__init__()方法 如果__init__()方法为 class Cat(): def __init__(self,num) : self.num=num Python中类的__init__( ...

  5. C#winform和百度API互动-----之JS读取中C#中的函数

    例子1 线上JS var getcpylocation =window.external.getlocation(); map.centerAndZoom(getcpylocation,12); C# ...

  6. tomcat部署web项目的问题

    1:启动窗口乱码 原因 Tomcat默认都是UTF-8的,但是控制台是GBK的,要保持一致 解决办法 打开tomcat目录下的conf/目录下logging.properties找到java.util ...

  7. 安装mysql问题解决

    [root@apollo init.d]# /etc/init.d/mysqld startmy_print_defaults: Can't read dir of '/etc/my.cnf.' (E ...

  8. CSS3常用属性及效果汇总

    本文转载于<https://blog.csdn.net/lyznice/article/details/54575905> 一.2D效果属性 要使用这些属性,我们需要通过 transfor ...

  9. Jmeter之分布式部署测试

    在使用Jmeter进行性能测试时,因受单机电脑的配置限制,可能无法支持较大数量的并发,此时就需要使用Jmeter提供的分布式测试的功能. jmeter分布式测试的执行原理是选择一台作为调度机,其他机器 ...

  10. VLC-DSS搭建直播系统中链路断开影响测试

    VLC-DSS搭建直播系统中链路断开影响测试 系统环境搭建如图所示.计算机77上运行VLC从摄像机51上取流,推送给一级DSS服务器30:二级DSS服务器78从一级DSS服务器30上取流转发.(其配置 ...