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

前言

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

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

(0)

相关推荐

  • .net core项目中常用的几款类库详解(值得收藏)

    前言 至2002微软公司推出.NET平台已近15年,在互联网快速迭代的浪潮中,许多语言已被淘汰,同时也有更多新的语言涌现,但 .Net 依然坚挺的站在系统开发平台的一线阵营中,并且随着.NET Core正式版的到来,迎来新一轮春天. 本文主要给大家介绍了关于.net core项目中常用的几款类库的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 汉字转拼音 1. HxfPinYin 这是我自己根据网上大神提供的源码,再.net core 框架下编译出的类库 主要提供汉字

  • Asp.net Core与类库读取配置文件信息的方法

    前言 首先开一个脑洞,Asp.net core 被使用这么长时间了,但是关于配置文件(json)的读取,微软官方似乎并没有给出像.net framework读取web.config那样简单且完美.严重怀疑这是微软为了促进.net core 生态繁荣搞的一点小手段. appsetting.Development.json (appsetting.json的内容和这个差不多,下面会讲到多环境使用) { "SettingPath": { "VideoFilePath":

  • 在.NET Core类库中使用EF Core迁移数据库到SQL Server的方法

    前言 如果大家刚使用EntityFramework Core作为ORM框架的话,想必都会遇到数据库迁移的一些问题. 起初我是在ASP.NET Core的Web项目中进行的,但后来发现放在此处并不是很合理,一些关于数据库的迁移,比如新增表,字段,修改字段类型等等,不应该和最上层的Web项目所关联,数据的迁移文件放到这里也感觉有点多余,有点乱乱的感觉,所以才想着单独出来由专门的项目进行管理会比较好,也比较清晰! 注意目标框架选择的是.NET Core 2.0而不是.NET Standard 2.0.

  • 如何在ASP.NET Core类库项目中读取配置文件详解

    前言 最近有朋友问如何在.net core类库中读取配置文件,当时一下蒙了,这个提的多好,我居然不知道,于是这两天了解了相关内容才有此篇文章的出现,正常来讲我们在应用程序目录下有个appsettings.json文件对于相关配置都会放在这个json文件中,但是要是我建立一个类库项目,对于一些配置比如密钥或者其他需要硬编码的数据放在JSON文件中,在.net core之前配置文件为web.config并且有相关的类来读取节点上的数据,现如今在.net core中为json文件,那么我们该如何做?本

  • ASP.NET Core使用微软官方类库实现汉字转拼音

    本文实例为大家分享了ASP.NET Core实现汉字转拼音的具体代码,供大家参考,具体内容如下 一.NuGet包 拼音:Install-Package PinYinConverterCore 简体-繁体互转:Install-Package TraditionalChineseToSimplifiedConverter 二.C#代码 class Program { static void Main(string[] args) { string Name= "刘大大"; Console.

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

    前言 aop即是面向切面编程,众多Aop框架里Castle是最为人所知的,另外还有死去的Spring.NET,当然,.NET Core社区新秀AspectCore在性能与功能上都非常优秀,已经逐渐被社区推崇和有越来越多的人使用.感谢柠檬同学的礼物! 如果大家出于自身需求或者学习,想实现一个Aop,是不是觉得一来就要使用Emit去做?最近我了解到了System.Reflection.DispatchProxy这个corefx类库,已经实现了动态代理功能. 1|1System.Reflection.

  • .NET Core类库项目中读取appsettings.json配置的方法

    这是一位朋友问我的问题,写篇随笔回答一下.有2种方法,一种叫丑陋的方法 ——IConfiguration ,一种叫优雅的方法 —— IOptions . 1)先看丑陋的方法 比如在RedisClient 中需要读取appsettings.json 中的 redis 连接字符串: { "redis": { "ConnectionString": "xxx" } } 需要在RedisClient 的构造函数参数中添加IConfiguration 接口

  • ASP.NET Core命名空间System.Text.Encodings.Web介绍

    System.Text.Encodings.Web 空间包含表示 Web 编码器的基类.表示 HTML.JavaScript 和 Url 字符编码的子类,以及表示仅允许编码特定字符.字符范围或码位的筛选器的类. [ 定义来自 microsoft ] 该命名空间有五个类,用于不同对象的编码处理. 五个类 HtmlEncoder 表示 HTML 字符编码. JavaScriptEncoder 表示 JavaScript 字符编码. TextEncoder Web 编码器的基类. TextEncode

  • C#中的反射(System.Reflection)

    一.获取程序集Assembly 1.获取当前运行的程序集 System.Reflection.Assembly[] asm = AppDomain.CurrentDomain.GetAssemblies(); // Assembly b = Assembly.GetExecutingAssembly(); 2.获取指定文件的程序集:Load,LoadFrom,LoadFile方法. Assembly c = Assembly.Load("mscorlib.dll");//如果你引用了程

  • .net Core 3.0 WebApi 创建Linux守护进程的方法

    前言 我们一般可以在Linux服务器上执行 dotnet <app_assembly.dll> 命令来运行我们的.net Core WebApi应用.但是这样运行起来的应用很不稳定,关闭终端窗口之后,应用也会停止运行.为了让其可以稳定运行,我们需要让它变成系统的守护进程,成为一种服务一直在系统中运行,出现异常时也能重新启动. Linux系统有自己的守护进程管理工具 Systemd .systemd 是内核启动后的第一个用户进程,PID 为1,是所有其它用户进程的父进程.它直接与内核交互,性能出

  • jQuery简易时光轴实现方法示例

    本文实例讲述了jQuery简易时光轴实现方法.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>timeLine</title> <style> body{ margin: 0; padding: 0; background: #e8ffe8; } #head, #content, #footer{ width: 100

  • C#利用System.Uri转URL为绝对地址的方法

    本文实例讲述了C#利用System.Uri转URL为绝对地址的方法.分享给大家供大家参考.具体分析如下: 在使用ASPOSE.Word生成Word文档时可以通过InsertHtml(html)来将图文信息写入Word文档(图片内嵌),但要求html里图片的src是绝对全路径,所以需要对html进行转化. 获取html可以来自数据库数据或者通过网络抓取,得到之后使用System.Uri来进行替换即可. 示例如下: Uri uri = new Uri(http://www.baidu.com); U

  • Python简易计算器制作方法代码详解

    主要用到的工具是Python中的Tkinter库 比较简单 直接上图形界面和代码 引用Tkinter库 from tkinter import * 建立主窗口对象 window=Tk() #设置窗口对象 window.title('counting machine') window.geometry("350x280") window['bg']='red' 建立标签框以及标签(将运算字符串显示在上面) frame=LabelFrame(window,bg='yellow',width

  • 仿照Element-ui实现一个简易的$message方法

    前言 在需要对用户进行提示时,有时会遇到这种场景:使用模态框提示太过硬核,使用toast提示又太轻了,这时候可以选择使用页面顶部滑下的消息提示.本文仿照element-ui的实现一个类似$message的方法. 思路梳理 首先我们来看下element-ui中消息提示的效果是怎么样的,找些思路. 从图中我们可以看消息提示是可以同时显示多条的,并且定位看起来都是fixed,居中展示,我们自然可以想到使用数组来存储这些消息的信息,并且根据每一条提示消息的显示隐藏更改每一项的top值,然后就是加一些动画

随机推荐