背景

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. hibernate_SessionFactory_getCurrentSession_JTA简介

    JTA:java transaction  api java里所规定的一种管理事务的API 在另一篇播客我写到了,SessionFactory需要关注两个方法, 即:  openSession     ...

  2. Linux下mysql基础命令(一)

    1, 创建mysqld数据库的管理用户:             要把root用户设置为管理员,我们应该运行下面的命令:    # mysqladmin -u root password 密码 一般情 ...

  3. HTML5 表单 中

    input 属性 autofocus 页面加载时自动获得焦点 required   非空字段输入框 placeholder 提供一种提示(hint),输入域为空时显示. pattern 规定验证inp ...

  4. 何为cookie?

    何为cookie HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上 ...

  5. springboot-2-ioc

    在spring环境下, ioc(控制反转 和 DI (依赖注入) 是等效的, 主要体现一种组合的松耦合思想. spring Ioc容器负责创建Bean, 并将Bean注入到所需的Bean中, 有xml ...

  6. Velocity工作原理解析和优化

    在MVC开发模式下,View离不开模板引擎,在Java语言中模板引擎使用得最多是JSP.Velocity和FreeMarker,在MVC编程开发模式中,必不可少的一个部分是V的部分.V负责前端的页面展 ...

  7. WPF中设置了WindowStyle="None"后,窗口仍然有边框的解决方法

    1. 设置了窗体的WindowStyle="None",窗口还是右边框,如下图: 2. 这是因为窗体默认是可以改变大小的,所以需要修改ResizeMode的值 ResizeMode ...

  8. CUBA与Spring相比,有很大的不同吗?

    原文:Developing with CUBA - a big shift from Spring? 翻译:CUBA China CUBA-Platform 官网 : https://www.cuba ...

  9. (二)JNI方法总结

    整个网上就没看到一个关于JNI好点的文档,干脆自己写一份,以方便以后使用的时候查阅 1. 类操作 DefineClass jclass DefineClass(JNIEnv *env, jobject ...

  10. 去除tableView表头悬浮

    UITableView设置为UITableViewStyleGrouped样式会出现多余间距,以前遇到过这样的问题,自己以为不难,只是一个知识点,也没太在意 ,今天又碰到了,发现自己把它给忘了,所以还 ...