• 利用.NET Core类库System.Reflection.DispatchProxy实现简易Aop


    背景

    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

  • 相关阅读:
    Android 安卓初探 新建项目
    SQL 根据关联,用一个表的值修改另一个表对应字段的值
    SQL 字符串不足补零
    Android 安卓学习积累
    C#中定义数组
    如何利用地图API制作汽车沿道路行驶的动画?——如何获得道路层数据
    Lambda 表达式(C# 编程指南)
    不定的多条件的过滤
    如何利用【百度地图API】,制作地图地址标记?
    php调用.net生成的.dll文件
  • 原文地址:https://www.cnblogs.com/ElderJames/p/implement-simple-Aop-using-a-dotnet-core-library-System-Reflection-DispatchProxy.html
Copyright © 2020-2023  润新知