公司动态

.NET里简易实现AOP

📅 2026/7/26 18:46:38
.NET里简易实现AOP
.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实践