.NET里简易实现AOP什么是AOP为什么需要它AOP面向切面编程是一种编程范式它允许我们将横切关注点如日志、权限、缓存、事务等与业务逻辑代码分离。在传统的面向对象编程OOP中这些横切关注点往往会散布在各个业务方法中导致代码重复、难以维护。AOP通过“切面”来统一处理这些关注点让业务代码更干净、更专注。想象一下你有一个订单服务每个方法都需要记录日志和检查权限。如果没有AOP你需要在每个方法里手动写日志和权限代码。有了AOP你只需要声明一个“切面”它会在方法执行前后自动执行这些通用操作。## .NET中实现AOP的方式在.NET生态中实现AOP有多种方式-使用框架如Castle Windsor、Autofac依靠动态代理、PostSharp编译时织入。-手动实现通过装饰器模式、动态代理DispatchProxy或RealProxy.NET Framework。本文重点介绍一种简易、无需第三方框架的方式使用.NET内置的DispatchProxy类。它轻量、易理解适合初学者和小型项目。## 简易实现基于DispatchProxy的AOPDispatchProxy是.NET Core/5中提供的类位于System.Reflection.DispatchProxy命名空间。它能动态生成一个代理类拦截所有接口方法的调用。我们只需要继承它并重写Invoke方法。### 步骤1定义接口和业务类首先我们需要一个接口因为DispatchProxy只能代理接口和一个实现类。csharp// 定义业务接口public interface IOrderService{ void CreateOrder(string productName, int quantity); string GetOrderStatus(int orderId);}// 业务实现类public class OrderService : IOrderService{ public void CreateOrder(string productName, int quantity) { Console.WriteLine($创建订单产品{productName}, 数量{quantity}); // 模拟耗时操作 Thread.Sleep(100); } public string GetOrderStatus(int orderId) { Console.WriteLine($查询订单状态订单ID{orderId}); // 模拟耗时操作 Thread.Sleep(200); return 已发货; }}### 步骤2创建AOP拦截器我们创建一个类继承DispatchProxy在Invoke方法中实现横切逻辑如日志记录、性能监控。csharpusing System.Reflection;public class LoggingAopProxyT : DispatchProxy where T : class{ private T _target; // 被代理的真实对象 // 工厂方法创建代理实例 public static T Create(T target) { // CreateT, LoggingAopProxyT() 会生成一个代理对象 var proxy CreateT, LoggingAopProxyT() as LoggingAopProxyT; proxy._target target; return proxy as T; } // 拦截所有接口方法调用 protected override object Invoke(MethodInfo targetMethod, object[] args) { // 前置处理记录方法调用信息 Console.WriteLine($[AOP] 开始执行方法{targetMethod.Name}); var stopwatch System.Diagnostics.Stopwatch.StartNew(); try { // 调用真实方法 var result targetMethod.Invoke(_target, args); stopwatch.Stop(); // 后置处理记录执行耗时 Console.WriteLine($[AOP] 方法 {targetMethod.Name} 执行完成耗时{stopwatch.ElapsedMilliseconds}ms); return result; } catch (Exception ex) { stopwatch.Stop(); Console.WriteLine($[AOP] 方法 {targetMethod.Name} 抛出异常{ex.Message}); throw; // 重新抛出异常保持调用链 } }}### 步骤3使用代理在主程序中通过工厂方法创建代理对象然后正常调用接口方法。csharpclass Program{ static void Main(string[] args) { // 创建真实对象 var realService new OrderService(); // 创建代理对象 var proxyService LoggingAopProxyIOrderService.Create(realService); Console.WriteLine( 调用 CreateOrder ); proxyService.CreateOrder(笔记本电脑, 2); Console.WriteLine(\n 调用 GetOrderStatus ); var status proxyService.GetOrderStatus(1001); Console.WriteLine($订单状态{status}); }}运行结果示例 调用 CreateOrder [AOP] 开始执行方法CreateOrder创建订单产品笔记本电脑, 数量2[AOP] 方法 CreateOrder 执行完成耗时104ms 调用 GetOrderStatus [AOP] 开始执行方法GetOrderStatus查询订单状态订单ID1001[AOP] 方法 GetOrderStatus 执行完成耗时203ms订单状态已发货## 进阶支持多个切面上面的例子只实现了一个切面日志性能监控。实际项目中可能需要多个切面如日志、权限、缓存。我们可以通过组合模式实现责任链。csharp// 定义一个通用的AOP拦截器基类public abstract class AopInterceptor : DispatchProxy{ protected abstract object InvokeInternal(MethodInfo method, object[] args, Funcobject next);}// 日志切面public class LoggingInterceptor : AopInterceptor{ protected override object InvokeInternal(MethodInfo method, object[] args, Funcobject next) { Console.WriteLine($[日志] 调用 {method.Name}); var result next(); Console.WriteLine($[日志] {method.Name} 返回); return result; }}// 权限切面public class AuthorizationInterceptor : AopInterceptor{ protected override object InvokeInternal(MethodInfo method, object[] args, Funcobject next) { // 模拟权限检查 Console.WriteLine($[权限] 检查 {method.Name} 的访问权限...); // 假设检查通过 return next(); }}// 使用责任链组合多个切面public class CompositeProxyT : DispatchProxy where T : class{ private T _target; private ListAopInterceptor _interceptors new(); public static T Create(T target, params AopInterceptor[] interceptors) { var proxy CreateT, CompositeProxyT() as CompositeProxyT; proxy._target target; proxy._interceptors.AddRange(interceptors); return proxy as T; } protected override object Invoke(MethodInfo targetMethod, object[] args) { // 构建责任链 Funcobject chain () targetMethod.Invoke(_target, args); // 从后往前包裹保证执行顺序 for (int i _interceptors.Count - 1; i 0; i--) { var currentInterceptor _interceptors[i]; var next chain; chain () currentInterceptor.InvokeInternal(targetMethod, args, next); } return chain(); }}使用方式csharpvar realService new OrderService();var proxy CompositeProxyIOrderService.Create( realService, new AuthorizationInterceptor(), new LoggingInterceptor());proxy.CreateOrder(鼠标, 5);输出[权限] 检查 CreateOrder 的访问权限...[日志] 调用 CreateOrder创建订单产品鼠标, 数量5[日志] CreateOrder 返回## 总结本文通过.NET内置的DispatchProxy类展示了一种无第三方依赖的简易AOP实现。核心思想是动态生成代理类在Invoke方法中插入横切逻辑。这种方式适合- 小型项目或原型开发- 需要快速实现日志、监控等简单切面- 学习AOP原理当然它也有局限性只能代理接口、无法拦截非虚方法、性能略低于编译时织入。对于大型项目建议使用成熟的框架如Castle Windsor或PostSharp。AOP的核心价值在于分离关注点让业务代码更专注于核心逻辑。无论使用哪种方式理解其思想比工具本身更重要。希望本文能帮助你快速上手.NET中的AOP实践
企业数字化 ERP 产品动态
相关推荐
Chat2DB终极指南:AI驱动的数据库管理工具完整对比分析 Chat2DB终极指南:AI驱动的数据库管理工具完整对比分析 【免费下载链接】Chat2DB 🔥🔥🔥 AI-driven database tool and SQL client, The hottest GUI client, supporting MySQL, Oracle, PostgreSQL, DB2, SQL Server, DB2, SQLite… · 2026/11/5 9:12:10
Ollama 在医疗文本结构化中的应用:病历实体抽取与 ICD 编码推荐的精度优化 Ollama 在医疗文本结构化中的应用:病历实体抽取与 ICD 编码推荐的精度优化
一、病历文本的结构化挑战
电子病历(EMR)的非结构化文本是医疗 AI 最难处理的数据类型。一份住院病历包含主诉、现病史、既往史、体格检查、辅助检查、诊断等 6~12 个… · 2026/9/19 16:16:38
Rust 在医疗设备软件开发中的安全认证价值:IEC 62304 与内存安全保证 Rust 在医疗设备软件开发中的安全认证价值:IEC 62304 与内存安全保证
一、医疗软件的安全认证困境
医疗设备软件(SaMD: Software as a Medical Device)的故障可能导致患者死亡。1990 年代 Therac-25 放射治疗机器的软件竞态条件导致 6 名患者… · 2026/10/31 17:38:00
EtherCAT从入门到精通(4) 接前一篇文章:EtherCAT从入门到精通(3) 本文内容参考:
EtherCAT 协议详细解析_ethercat通讯协议-CSDN博客
特此致谢! 二、认识
2. EtherCAT核心技术原理
(4)同步机制:分布式时钟… · 2026/11/5 9:12:03
AllData基于开源项目DataCap构建数据中枢平台,完成JDBC组件拖拽式数据集成多源数据互通,开箱即用 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 9:12:03
什么是加密货币凭证? /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 9:12:03
2026生活服务业小程序开发哪家强?门店商家选型参考 2026生活服务业小程序开发哪家强?门店商家选型参考据商务部公开数据,我国现有超3200万零售个体户,全国一刻钟便民生活圈试点已覆盖195.4万个商业网点,服务居民1.68亿人;QuestMobile《2026全景生态流量春季报告》显示&a… · 2026/11/5 9:12:03
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38