提示:以下是本篇文章正文内容,下面案例可供参考

一、基本概念

1)代理设计模式:为其他对象提供一种代理,以控制对这个对象的访问。
2)代理分类:

  • 远程代理:为一个对象在不同的地址空间,提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。客户端调用Web服务,会生成WebReference文件和文件夹,WebReference就是代理,使得客户端可以实现远程访问等功能。
  • 虚拟代理,如果要创建开销很大的对象,可以通过代理来存放实例化需要很长时间的真实对象。打开一个很大的网页,除了文字先出现外,图片和视频等都是慢慢出现的。查询某个部门下所有的员工的信息,姓名、性别、年龄、毕业院校、部门、照片、slogen…
  • 安全代理,用来控制真实对象的访问权限。例如订单系统,要求是:一旦订单被创建,只有订单的创建人才可以修改订单中的数据,其他人则不能修改

二、代码示例

普通代理

一个非常简单的例子

public class Swim
{
    public virtual void Go()
    {
        Console.WriteLine("开始游泳!!!");
    }
}

public class SwimProxy:Swim
{
    public override void Go()
    {
         //目标方法执行前
        Console.WriteLine("先进性热身运动!!!");
        base.Go();
        //目标方法执行后
        Console.WriteLine("开始洗澡!!!");
    }
}

使用案例

SwimProxy swimProxy = new SwimProxy();
swimProxy.Go();

通过代理模式,在目标方法执行前,执行后进行处理,甚至可以要求传入参数,来判断年纪过大不允许游泳,如果要这么做,做一些权限管控,可以使用非继承的方式,内部声明Swim对象即可。

动态代理

在编译期间不生成代理,而是在执行期间,动态创建代理类。

DispatchProxy基本使用

DispatchProxy是一个基于接口的动态代理工具类。
1)使用要求:如果当前类允许动态代理,则必须实现一个业务接口
2)注意:

  • 动态代理生成的动态类对象是业务接口类型对象,所以只有实现了接口方法的具体方法才会被监听到执行
  • 当前类的其他virtual方法如果不是来自业务接口,由于生成的代理对象是业务接口类型,无法调用
    3)代码演示
/// <summary>
/// 一个接口
/// </summary>
public interface Sport
{
    public void Swim();
    public void Run();
}

/// <summary>
/// 实现类
/// </summary>
public class SportImpl: Sport
{
    public void Swim()
    {
        Console.WriteLine("开始游泳!!!");
    }

    public void Run()
    {
        Console.WriteLine("跑步");
    }

    public void Run1()
    {
        Console.WriteLine("跑步");
    }
}

/// <summary>
/// 实现类的动态代理类
/// </summary>
public class SportProxy : DispatchProxy
{
    private SportImpl im=new SportImpl();
    protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
    {
        //目标方法执行前
        Console.WriteLine("目标方法执行前" + targetMethod.Name);


        //目标方法执行
        targetMethod.Invoke(im, args);


        //目标方法执行后
        Console.WriteLine("目标方法执行后" + targetMethod.Name);

        return 0;
    }
}

使用代码

 Sport sport = SportProxy.Create<Sport,SportProxy>();
            
sport.Swim();
sport.Run();

DispatchProxy总结

1)如果我们每个类都需要代理,那么我们就要给每个类写一个代理类,显然是非常麻烦的
2)使用DispatchProxy需要的条件如下:

  • 一个接口
  • 一个实现了此接口的实现类
  • 一个操作对象,用于代理类在真正执行时,需要调用的对象
    3)代码示例
/// <summary>
/// 一个接口
/// </summary>
public interface Sport
{
    public void Swim();
    public void Run();
}

/// <summary>
/// 实现类
/// </summary>
public class SportImpl: Sport
{
    public void Swim()
    {
        Console.WriteLine("开始游泳");
    }

    public void Run()
    {
        Console.WriteLine("开始跑步");
    }

    public virtual void Run1()
    {
        Console.WriteLine("跑步1");
    }
}
/// <summary>
/// 通用动态代理类
/// </summary>
/// <typeparam name="TI">接口类型</typeparam>
/// <typeparam name="TImpl">实现接口的具体类类型</typeparam>
public class DynamicProxy<TI,TImpl>
{
    /// <summary>
    /// 操作对象
    /// </summary>
    public TI invokeObj { get; private set; }
    
    public DynamicProxy(TImpl implObj)
    {
        if (implObj != null)
        {
            InnerProxy.implObj = implObj;
            this.invokeObj = InnerProxy.Create<TI, InnerProxy>();
        }
    }

    /// <summary>
    /// 设置方法执行前执行的代码
    /// </summary>
    /// <param name="action"></param>
    /// <returns></returns>
    public DynamicProxy<TI, TImpl> SetBefore(Action<MethodInfo, object?[]?> action)
    {
        InnerProxy.before = action;
        return this;
    }

    public DynamicProxy<TI, TImpl> SetAfter(Action<MethodInfo, object?[]?> after)
    {
        InnerProxy.after = after;
        return this;
    }

    /// <summary>
    /// 设置方法执行后执行的代码
    /// </summary>
    public class InnerProxy : DispatchProxy
    {
        public static TImpl implObj { get; set; }
        public static Action<MethodInfo, object?[]?> before { get; set; }
        public static Action<MethodInfo, object?[]?> after { get; set; }
        protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
        {
            before(targetMethod,args);
            var result=targetMethod.Invoke(implObj, args);
            after(targetMethod, args);
            return result;
        }
    }
}

使用案例

DynamicProxy<Sport, SportImpl> dynamicProxy = new DynamicProxy<Sport, SportImpl>(new SportImpl());
dynamicProxy.SetBefore((method, args) =>
{
    Console.WriteLine("方法执行前...");
}).SetAfter((method, args) =>
{
    Console.WriteLine("方法执行后...");
}).invokeObj.Swim();
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐