利用.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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM