.NET Core类库System.Reflection.DispatchProxy实现简易Aop的方法

所属分类: 网络编程 / ASP.NET 阅读数: 210
收藏 0 赞 0 分享

前言

aop即是面向切面编程,众多Aop框架里Castle是最为人所知的,另外还有死去的Spring.NET,当然,.NET Core社区新秀AspectCore在性能与功能上都非常优秀,已经逐渐被社区推崇和有越来越多的人使用。感谢柠檬同学的礼物!

如果大家出于自身需求或者学习,想实现一个Aop,是不是觉得一来就要使用Emit去做?最近我了解到了System.Reflection.DispatchProxy这个corefx类库,已经实现了动态代理功能。

1|1System.Reflection.DispatchProxy

下面演示一下它的使用方法:

class Program
{
 static void Main(string[] args)
 {
  //创建代理类,并把SampleProxy作为拦截器注入
  var sampleProxy = (targetInterface)SampleProxy.Create<targetInterface, SampleProxy>();
  //执行接口方法
  sampleProxy.Write("here is invoke by proxy");
 }
}

//需要被生成代理实例的接口
public interface targetInterface
{
 //这个方法会被代理类实现
 void Write(string writesomeshing);
}

public class SampleProxy : DispatchProxy
{
 /// <summary>
 /// 拦截调用
 /// </summary>
 /// <param name="method">所拦截的方法信息</param>
 /// <param name="parameters">所拦截方法被传入的参数指</param>
 /// <returns></returns>
 protected override object Invoke(MethodInfo targetMethod, object[] args)
 {
  Console.WriteLine(args[0]);
  return null;
 }
}

2|0改造成一款简易AOP

2|1为什么?

System.Reflection.DispatchProxy只有一个Api,就是objecct Create<T,TProxy>() where TProxy:DispatchProxy,约束了只能传入泛型参数,并不能从方法传入类型,这就会带来很多问题。而更可气的是,给官方提了issue之后,还是不给增加这个api……

2|2改造方法

幸好,在那个issue下,issue作者提供了一个解决方案,就是用反射来构造这个泛型方法。我还在这基础上,封装了一下,加入了传入拦截器实例和传入拦截器构造方法参数的功能。

/// <summary>
/// 拦截器接口
/// </summary>
public interface IInterceptor
{
 /// <summary>
 /// 拦截器调用
 /// </summary>
 /// <param name="target">代理实例</param>
 /// <param name="method">所拦截的方法</param>
 /// <param name="parameters">所拦截方法传入的参数值</param>
 /// <returns>返回值会传递给方法返回值</returns> 
 object Intercept(object target, MethodInfo method, object[] parameters);
}

拦截器要实现这个接口,下面是对DispatchProxy的封装,实现更多创建代理实例的方法

public class ProxyGenerator : DispatchProxy
{
 private IInterceptor interceptor { get; set; }

 /// <summary>
 /// 创建代理实例
 /// </summary>
 /// <param name="targetType">所要代理的接口类型</param>
 /// <param name="interceptor">拦截器</param>
 /// <returns>代理实例</returns>
 public static object Create(Type targetType, IInterceptor interceptor)
 {
  object proxy = GetProxy(targetType);
  ((ProxyGenerator)proxy).CreateInstance(interceptor);
  return proxy;
 }

 /// <summary>
 /// 创建代理实例
 /// </summary>
 /// <param name="targetType">所要代理的接口类型</param>
 /// <param name="interceptorType">拦截器类型</param>
 /// <param name="parameters">拦截器构造函数参数值</param>
 /// <returns>代理实例</returns>
 public static object Create(Type targetType, Type interceptorType, params object[] parameters)
 {
  object proxy = GetProxy(targetType);
  ((ProxyGenerator)proxy).CreateInstance(interceptorType, parameters);
  return proxy;
 }


 /// <summary>
 /// 创建代理实例 TTarget:所要代理的接口类型 TInterceptor:拦截器类型
 /// </summary>
 /// <param name="parameters">拦截器构造函数参数值</param>
 /// <returns>代理实例</returns>
 public static TTarget Create<TTarget, TInterceptor>(params object[] parameters) where TInterceptor : IInterceptor
 {
  var proxy = GetProxy(typeof(TTarget));
  ((ProxyGenerator)proxy).CreateInstance(typeof(TInterceptor), parameters);
  return (TTarget)proxy;
 }

 private static object GetProxy(Type targetType)
 {
  var callexp = Expression.Call(typeof(DispatchProxy), nameof(DispatchProxy.Create), new[] { targetType, typeof(ProxyGenerator) });
  return Expression.Lambda<Func<object>>(callexp).Compile()();
 }

 private void CreateInstance(Type interceptorType, object[] parameters)
 {
  var ctorParams = parameters.Select(x => x.GetType()).ToArray();
  var paramsExp = parameters.Select(x => Expression.Constant(x));
  var newExp = Expression.New(interceptorType.GetConstructor(ctorParams), paramsExp);
  this.interceptor = Expression.Lambda<Func<IInterceptor>>(newExp).Compile()();
 }

 private void CreateInstance(IInterceptor interceptor)
 {
  this.interceptor = interceptor;
 }

 protected override object Invoke(MethodInfo method, object[] parameters)
 {
  return this.interceptor.Intercept(method, parameters);
 }
}

2|3使用方法

 class Program
 {
  static void Main(string[] args)
  {
   var poxy1 = (targetInterface)ProxyGenerator.Create(typeof(targetInterface), new SampleProxy("coreproxy1"));
   poxy1.Write("here was invoked"); //---> "here was invoked by coreproxy1"

   var poxy2 = (targetInterface)ProxyGenerator.Create(typeof(targetInterface), typeof(SampleProxy), "coreproxy2");
   poxy2.Write("here was invoked"); //---> "here was invoked by coreproxy2"

   var poxy3 = ProxyGenerator.Create<targetInterface, SampleProxy>("coreproxy3");
   poxy3.Write("here was invoked"); //---> "here was invoked by coreproxy3"
  }
 }


 public class SampleProxy : IInterceptor
 {
  private string proxyName { get; }

  public SampleProxy(string name)
  {
   this.proxyName = name;
  }

  public object Intercept(MethodInfo method, object[] parameters)
  {
   Console.WriteLine(parameters[0] + " by " + proxyName);
   return null;
  }
 }

 public interface targetInterface
 {
  void Write(string writesome);
 }

3|0总结

总结一下就是,微软爸爸给我们的这个轮子还是即轻便又很好用的。

本文的实例代码可以在我的github上找到:https://github.com/ElderJames/CoreProxy

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

更多精彩内容其他人还在看

解析WPF实现音频文件循环顺序播放的解决方法

本篇文章是对WPF实现音频文件循环顺序播放的方法进行了详细的分析介绍,需要的朋友参考下
收藏 0 赞 0 分享

解决.net framework 4.0环境下遇到版本不同编译不通过的方法详解

本篇文章是对.net framework 4.0环境下遇到版本不同编译不通过的解决方法进行了详细的分析介绍,需要的朋友参考下
收藏 0 赞 0 分享

将文件上传、下载(以二进制流保存到数据库)实现代码

将文件以二进制流的格式写入数据库:首先获得文件路径,然后将文件以二进制读出保存在一个二进制数组中具体请祥看本文,希望对你有所帮助
收藏 0 赞 0 分享

点击提交按钮后DropDownList的值变为默认值实现分析

在点击提交按钮后,页面上所有的绑定到数据库的控件值都恢复到默认值,下面与大家分享下DropDownList的值变为默认值
收藏 0 赞 0 分享

ASP.NET web.config中数据库连接字符串connectionStrings节的配置方法

ASP.NET web.config中数据库连接字符串connectionStrings节的配置方法,需要的朋友可以参考一下
收藏 0 赞 0 分享

Linkbutton控件在项目中的简单应用

Button控件可分为button控件、LinkButton控件、ImageButton控件三类,而LinkButton控件则在页面上显示为一个超级链接,下面与大家分享下其具体应用
收藏 0 赞 0 分享

Web.config 和 App.config 的区别分析

Web.config 和 App.config 的区别分析,需要的朋友可以参考一下
收藏 0 赞 0 分享

基于.Net中的数字与日期格式化规则助记词的使用详解

本篇文章是对.Net中的数字与日期格式化规则助记词的使用进行了详细的分析介绍,需要的朋友参考下
收藏 0 赞 0 分享

解决在Web.config或App.config中添加自定义配置的方法详解

本篇文章是对在Web.config或App.config中添加自定义配置的方法进行了详细的分析介绍,需要的朋友参考下
收藏 0 赞 0 分享

深入本机影像生成器(Ngen.exe)工具使用方法详解

本篇文章是对本机影像生成器(Ngen.exe)工具使用方法进行了详细的分析介绍,需要的朋友参考下
收藏 0 赞 0 分享
查看更多