背景

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

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

System.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;
}
}

改造成一款简易AOP

为什么?

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

改造方法

幸好,在那个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);
}
}

使用方法

    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);
}

总结

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

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

利用.NET Core类库System.Reflection.DispatchProxy实现简易Aop的更多相关文章

  1. 利用system.reflection遍历一个类的变量成员

    假设有下面一个类,在程序中已初始化,如何获取里面的变量成员name,age,onduty及其值呢? public class Employee { public string name; public ...

  2. 使用.net core中的类DispatchProxy实现AOP

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是软件开发中的一个热点,利用A ...

  3. Asp.net core下利用EF core实现从数据实现多租户(1)

    前言 随着互联网的的高速发展,大多数的公司由于一开始使用的传统的硬件/软件架构,导致在业务不断发展的同时,系统也逐渐地逼近传统结构的极限. 于是,系统也急需进行结构上的升级换代. 在服务端,系统的I/ ...

  4. System.Reflection 获取描述

    我们需要获取类,属性,方法的描述.这个跟获取枚举的描述一样,需要我们通过反射来做.这还需要我们的利用System.ComponentModel:Description  的属性来完成. 新建一个类:使 ...

  5. C#反射实例(一) 利用反射使用类库

    在网上查找了不少的资料,可以说大同小异,概念性的东西网上一搜一堆,今天把反射的东西整理了一下,供大家使用,我保证我这里是最全面的东西,当然也是基础的东西,在学好了这一切的基础上,大家可以学习反射的具体 ...

  6. 如何将一个.NET Core类库发布到NuGet

    包治百病 | 如何将一个.NET Core类库发布到NuGet 写文章 包治百病 | 如何将一个.NET Core类库发布到NuGet Edi Wang发表于汪宇杰博客订阅 77 NuGet是.NET ...

  7. Asp.net core下利用EF core实现从数据实现多租户(3): 按Schema分离 附加:EF Migration 操作

    前言 前段时间写了EF core实现多租户的文章,实现了根据数据库,数据表进行多租户数据隔离. 今天开始写按照Schema分离的文章. 其实还有一种,是通过在数据表内添加一个字段做多租户的,但是这种模 ...

  8. 【asp.net core 系列】8 实战之 利用 EF Core 完成数据操作层的实现

    0. 前言 通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口.这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方. 1. 添加EF Core 先 ...

  9. Could not load type 'System.Reflection.AssemblySignatureKeyAttribute' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c

    错误: Could not load type 'System.Reflection.AssemblySignatureKeyAttribute' from assembly 'mscorlib, V ...

随机推荐

  1. Spring Boot的filter简单使用

    过滤器(Filter)的注册方法和 Servlet 一样,有两种方式:代码注册或者注解注册 1.代码注册方式 通过代码方式注入过滤器 @Bean     public FilterRegistrati ...

  2. git 学习之撤销和删除

    在实际的工作和学习中我们经常的会对文件进行修改,但是或多或少的就会发现由于某些原因修改是错误的这时候就需要对所做的修改进行撤销,更或者某些时候需要对文件进行删除.本节就会告诉大家如何操作. 撤销操作 ...

  3. PHP之string之str_word_count()函数使用

    str_word_count (PHP 4 >= 4.3.0, PHP 5, PHP 7) str_word_count - Return information about words use ...

  4. leetcode1:线性表

    //定义二维数组int **array = new int*[row_num]; ;i<row_num;i++) { array[i] = new int[col_num]; } vector& ...

  5. ReferenceError: “alert” is not defined

    用Node.js单独运行js文件时,其中定义的alert不可用 alert is not part of JavaScript, it's part of the window object prov ...

  6. 【LeetCode题解】349_两个数组的交集

    目录 [LeetCode题解]349_两个数组的交集 描述 方法一:两个哈希表 Java 实现 类似的 Java 实现 Python 实现 类似的 Python 实现 方法二:双指针 Java 实现 ...

  7. 【转】Emgu CV on C# (五) —— Emgu CV on 局部自适应阈值二值化

    局部自适应阈值二值化 相对全局阈值二值化,自然就有局部自适应阈值二值化,本文利用Emgu CV实现局部自适应阈值二值化算法,并通过调节block大小,实现图像的边缘检测. 一.理论概述(转载自< ...

  8. ListView和BaseAdapter

    参考资料:http://www.runoob.com/w3cnote/android-tutorial-listview.html <LinearLayout xmlns:android=&qu ...

  9. [转]C#中Timer使用及解决重入问题

    本文转自:http://www.cnblogs.com/hdkn235/archive/2014/12/27/4187925.html ★前言 打开久违的Live Writer,又已经好久没写博客了, ...

  10. var、let、const的区别,以及作用范围。

    在es5中一般经常使用的变量有两个级别,一个是用var声明的全局级别的变量,另外一个是函数级别是用var生命在函数内的.本文中将详细讲解我对es6中的const和let的区别. let的使用以及作用范 ...