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

Author Avatar
James Yeung 9月 01, 2018
  • 在其它设备中阅读本文章

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

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

下面演示一下它的使用方法:

class Program
{
    static void Main(string[] args)
    {
        //创建代理类,并把SamepleProxy作为拦截器注入
        var samepleProxy = (targetInterface)SamepleProxy.Create<targetInterface, SamepleProxy>();
        //执行接口方法
        samepleProxy.Write("here is invoke by proxy");
    }
}

//需要被生成代理实例的接口
public interface targetInterface
{
    //这个方法会被代理类实现
    void Write(string writesomeshing);
}

public class SamepleProxy : 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;
    }
}

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; }
    private static object proxy { 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);
        MethodInfo method = typeof(ProxyGenerator).GetMethod(nameof(CreateInstance), BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, new[] { typeof(IInterceptor) }, null);
        method.Invoke(proxy, new object[] { 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);
        MethodInfo method = typeof(ProxyGenerator).GetMethod(nameof(CreateInstance), BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, new[] { typeof(Type), typeof(object[]) }, null);
        method.Invoke(proxy, new object[] { 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
    {
        object proxy = GetProxy(typeof(TTarget));
        MethodInfo method = typeof(ProxyGenerator).GetMethod(nameof(CreateInstance), BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, new[] { typeof(Type), typeof(object[]) }, null);
        method.Invoke(proxy, new object[] { typeof(TInterceptor), parameters });
        return (TTarget)proxy;
    }

    private static object GetProxy(Type targetType)
    {
        MethodInfo method = typeof(DispatchProxy).GetMethod(nameof(DispatchProxy.Create), new Type[] { });
        method = method.MakeGenericMethod(targetType, typeof(ProxyGenerator));
        proxy = method.Invoke(null, null);
        return proxy;
    }

    private void CreateInstance(Type interceptorType, object[] parameters)
    {
        this.interceptor = (IInterceptor)Activator.CreateInstance(interceptorType, parameters);
    }

    private void CreateInstance(IInterceptor interceptor)
    {
        this.interceptor = interceptor;
    }

    protected override object Invoke(MethodInfo method, object[] parameters)
    {
        return this.interceptor.Intercept(proxy, method, parameters);
    }
}

使用方法:

class Program
{
    static void Main(string[] args)
    {
        // var poxy = (targetInterface)ProxyGenerator.Create(typeof(targetInterface), new SamepleProxy());
        // 或
        //var poxy = (targetInterface)ProxyGenerator.Create(typeof(targetInterface), typeof(SamepleProxy));
        // 或
        var poxy = ProxyGenerator.Create();
        poxy.Write("here is invoked by coreproxy");
    }
}


public class SamepleProxy : IInterceptor
{
    public object Intercept(object target, MethodInfo method, object[] parameters)
    {
        Console.WriteLine(parameters[0]);
        return null;
    }
}

public interface targetInterface
{
    void Write(string writesome);
}

总结一下就是,微软爸爸给我们的这个轮子还是即轻便又很好用的。
本文的实例代码可以在我的github上找到:https://github.com/ElderJames/CoreProxy

本文原创授权为:署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0) 协议普通文本 | 协议法律文本
本文链接:https://yangshunjie.com/implement-simple-Aop-using-a-dotnet-core-library-System-Reflection-DispatchProxy.html