首页 > 其他分享 >.NET 代理模式(二) 动态代理-DynamicProxy

.NET 代理模式(二) 动态代理-DynamicProxy

时间:2024-04-03 14:57:56浏览次数:23  
标签:DynamicProxy Invoke Create 代理 DispatchProxy NET 方法 public

前言

我们都知道,在.NET中实现动态代理AOP有多种方案,也有很多框架支持,但大多框架的实现原理都是通过Emit配合Activator一起使用,从IL级别上实现动态代理。

其实在.NET中有一个更为简单的方案可以实现动态代理,那就是DispatchProxy 类。

DispatchProxy 类

DispatchProxy 类是 .NET Core 2.1 引入的一种动态代理机制(.net frameowrk 早已支持),用于创建代理对象来处理实现了特定接口的目标对象的调用。这个类主要用于实现透明代理,允许你在调用目标对象的方法前后执行额外的逻辑,例如日志记录、性能监控等。

要使用 DispatchProxy 类,你需要创建一个继承自 DispatchProxy 的代理类,并实现一个抽象方法 Invoke,该方法会被调用以处理目标对象的方法调用。你可以在 Invoke 方法中编写额外的逻辑,然后使用 Create 方法来创建代理对象。

方法介绍

DispatchProxy 类主要有两个重要的方法,它们是 Create 和 Invoke。下面我将逐一解释这两个方法的作用:

  1. Create 方法:

    • public static T Create<T,TProxy>() where TProxy : DispatchProxy
    • 这个方法用于创建一个实现了指定接口的代理对象。
    • 参数 T 是目标对象所实现的接口类型,而 TProxy 是继承自 DispatchProxy 的代理类类型。
    • Create 方法返回的对象类型是 T,即代理对象。
    • 使用 Create 方法时,需要传入两个类型参数,其中 T 是接口类型,TProxy 是继承自 DispatchProxy 的代理类。
  2. Invoke 方法:

    • protected override object Invoke(MethodInfo targetMethod, object[] args)

    • 这个方法是一个抽象方法,需要在派生类中进行实现。

    • 当代理对象的方法被调用时,Invoke 方法会被调用,用于处理目标对象的方法调用。

    • 参数 targetMethod 是目标对象的方法信息,args 是方法调用时传入的参数数组。

    • Invoke 方法必须返回一个 object 对象,这是目标方法的返回值。

    • 在 Invoke 方法中,你可以编写额外的逻辑来处理方法调用,例如日志记录、性能监控等。

    • 如果代理对象的方法调用抛出了异常,可以在 Invoke 方法中捕获并处理这些异常。

总的来说,Create 方法用于创建代理对象,而 Invoke 方法用于处理目标对象的方法调用。使用这两个方法可以实现动态代理,对目标对象的方法调用进行拦截和处理,从而实现一些额外的功能,例如日志记录、权限验证等。

代码示例

如下代码是一个代理类(SubjectProxy)对接口(ISubject)的实现类(RealSubject)进行方法请求(Request)时,从而打印Console日志。

    using System;
    using System.Reflection;
    using System.Reflection.Emit;

    public class SubjectProxy : DispatchProxy
    {
        private ISubject _realSubject;


        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            Console.WriteLine("Before invoking the real subject.");
            var result = targetMethod.Invoke(_realSubject, args);
            Console.WriteLine("After invoking the real subject.");
            return result;
        }

        public static ISubject Create(ISubject realSubject)
        {
            object proxy = Create<ISubject, SubjectProxy>();
            ((SubjectProxy)proxy)._realSubject = realSubject;
            return (ISubject)proxy;
        }
    }

    public interface ISubject
    {
        void Request();
    }

    public class RealSubject : ISubject
    {
        public void Request()
        {
            Console.WriteLine("RealSubject handles the request.");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            ISubject realSubject = new RealSubject();
            ISubject proxy = SubjectProxy.Create(realSubject);
            proxy.Request();
        }
    }

具体输出如下:

Before invoking the real subject.
RealSubject handles the request.
After invoking the real subject.

如上代码中,如果我希望实现一个通用代理类,针对所有需要代理的实现类进行对应代理,该如何处理呢?

我们对如上代码进行基本优化

    using System;
    using System.Reflection;

    public class GenericProxy<T> : DispatchProxy where T : class
    {
        private T _realObject;

        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            Console.WriteLine($"GenericProxy Before invoking the real method  {targetMethod.Name}");
            var result = targetMethod.Invoke(_realObject, args);
            Console.WriteLine($"GenericProxy After invoking the real method {targetMethod.Name}");
            return result;
        }

        public static T Create(T realObject)
        {
            object proxy = Create<T, GenericProxy<T>>();
            ((GenericProxy<T>)proxy)._realObject = realObject;
            return (T)proxy;
        }
    }

    public interface ISubject01
    {
        void Request();
    }

    public class RealSubject01 : ISubject01
    {
        public void Request()
        {
            Console.WriteLine("RealSubject01 handles the request.");
        }
    }


    public interface ISubject02
    {
        void Request();
    }

    public class RealSubject02 : ISubject02
    {
        public void Request()
        {
            Console.WriteLine("RealSubject02 handles the request.");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ISubject01 realObject01 = new RealSubject01();
            ISubject01 proxy01 = GenericProxy<ISubject01>.Create(realObject01);
            proxy01.Request();

            ISubject02 realObject02 = new RealSubject02();
            ISubject02 proxy02 = GenericProxy<ISubject02>.Create(realObject02);
            proxy02.Request();

            Console.ReadLine();
        }
    }

如上图所示,可以将目标实现类,抽象为泛型T,这样就可以兼容多个实现类进行代理了。

输出结果:

GenericProxy Before invoking the real method  Request
RealSubject01 handles the request.
GenericProxy After invoking the real method Request
GenericProxy Before invoking the real method  Request
RealSubject02 handles the request.
GenericProxy After invoking the real method Request

DispatchProxy 的优缺点

优点:

  1. 高级抽象:DispatchProxy 提供了一个更高级的抽象,允许你以更简单的方式来实现动态代理,而不需要直接与 IL(Intermediate Language,中间语言)交互。
  2. 简化开发:使用 DispatchProxy,你可以直接通过实现接口来定义代理类的行为,而不需要了解底层的 IL 编程。
  3. 可读性:由于 DispatchProxy 提供了一个更高级的抽象,生成的代理类更容易理解和阅读。

缺点:

  1. 只能基于接口: DispatchProxy 只能代理接口而不能代理类。抽象类,封闭类都是无法代理的,这意味着你必须针对你的类型定义一个接口。
  2. 只能代理接口方法:由于DispatchProxy类基于接口代理,所以无法代理某些特定的方法,如静态方法、私有方法等。
  3. 高级功能局限:由于DispatchProxy类是高级抽象,所以可扩展性偏弱,如果需要复杂代理还是得用Emit和Activator进行。

标签:DynamicProxy,Invoke,Create,代理,DispatchProxy,NET,方法,public
From: https://www.cnblogs.com/dyhuang/p/18108712

相关文章

  • .NET Aspire 外部参数 (External parameters)
    .NETAspire外部参数(Externalparameters)https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/external-parameters环境提供应用运行的上下文。Parameter提供了在应用运行中请求外部值的功能。当应用本地运行的时候,Parameter可以为应用提供值,或者在应用部署的......
  • 基于donetcore/CAP实现分布式事务一致性
    官网:https://cap.dotnetcore.xyz相关介绍CAP是一个EventBus,同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架。它有助于创建可扩展,可靠并且易于更改的微服务系统。在微软的 eShop 微服务示例项目中,推荐使用CAP作为生产环境可用的EventBus。什么是Event......
  • 入门 .NET Aspire: 使用 .NET 简化云原生应用开发
    入门.NETAspire:使用.NET简化云原生应用开发https://devblogs.microsoft.com/dotnet/introducing-dotnet-aspire-simplifying-cloud-native-development-with-dotnet-8/经历多个版本之后,我们一直在朝着我们正在进行的理想目标之一取得进展。使.NET成为全球构建云原生应用......
  • 重庆天翼云代理商:分布式容器云平台面向多云、多集群等场景推出的企业级容器云平台
    重庆天翼云代理商:分布式容器云平台面向多云、多集群等场景推出的企业级容器云平台简介:飞机@luotuoemo本文由(天翼云代理商:【金推云】www.jintui.cn)撰写重庆天翼云代理商:分布式容器云平台在当今的信息化社会,一种名为“云计算”的技术正在逐渐改变我们生活和工作的方式。云......
  • 北京天翼云代理商:分布式消息服务MQTT面向终端设备的轻量级消息产品
    北京天翼云代理商:分布式消息服务MQTT面向终端设备的轻量级消息产品简介:飞机@luotuoemo本文由(天翼云代理商:【金推云】www.jintui.cn)撰写北京天翼云代理商:分布式消息服务MQTT面向终端设备的轻量级消息产品一、天翼云的优势天翼云是中国电信旗下的云计算和大数据服务品牌,依......
  • ENet——实时语义分割的深度神经网络架构与代码实现
    概述在移动设备上执行实时像素级分割任务具有重要意义。现有的基于分割的深度神经网络需要大量的浮点运算,并且通常需要较长时间才能投入使用。本文提出的ENet架构旨在减少潜在的计算负担。ENet在保持或提高分割精度的同时,相比现有的分割网络,速度提升了18倍,参数量减少了79倍......
  • 记录一次解决跨域问题解决过程。 strict-origin-when-cross-origin,net::ERR_FAILED, No
    事情是这样的,vue项目本地启动可以正常连接后端端口访问,部署到nginx上只有就无法访问,显示跨域问题  于是查看后端日志 啥都没有,觉得肯定是nginx的问题,怎么配置都没用, location/{ roothtml; indexindex.htmlindex.htm; add_header'Access-Control-Allow-O......
  • 在stable diffusion中如何分辨lora、大模型、controlnet
     LoRA(LowRankAdaptation)StableDiffusionLoRA是微软的研究人员为了解决大语言模型微调而开发的一项技术,它是一个多模态语言-图像模型,LORA可以学习将其语言表征迁移到图像modal中从而获得跨模态语义一致的表示。LoRA模型是Stable-Diffusion中的一个插件,仅需要少......
  • Advanced .Net Debugging 6:程序集加载器
    一、简介这是我的《Advanced.NetDebugging》这个系列的第六篇文章。这篇文章的内容是原书的第二部分的【调试实战】的第四章。这章主要讲的是程序集加载器,比如:CLR加载器简介、简单的程序集加载故障、加载上下文故障、互用性与DllNotFoundException和轻量级代码生成的......
  • .Net单元测试xUnit和集成测试指南(1)
    引言在现代化的软件开发中,单元测试和集成测试是确保代码质量和可靠性的关键部分。ASP.NETCore社区内提供了强大的单元测试框架,xUnit是其中之一,它提供了简单、清晰和强大的测试功能,编写单元测试有许多优点;有助于回归、提供文档及辅助良好的设计。下面几节我们来深入浅出探讨如......