翼度科技»论坛 编程开发 .net 查看内容

【设计】C#如何实现AOP 面向切面编程

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
一、AOP 由来
  1.     IUserHelper userHelper = new CommonUserHelper();<br>    // commonUser.Create中存在 方法执行前、方法执行后的业务逻辑
  2.     userHelper.Create("test0401_A");
  3.     public interface IUserHelper
  4.     {
  5.         void Create(string name);
  6.     }
  7.     public class CommonUserHelper : IUserHelper
  8.     {
  9.         private void before()
  10.         {
  11.             Console.WriteLine("CommonUser before");
  12.         }
  13.         private void after()
  14.         {
  15.             Console.WriteLine("CommonUser after");
  16.         }
  17.         public void Create(string name)
  18.         {
  19.             before();
  20.             Console.WriteLine($"  Common User : {name} Created !");
  21.             after();
  22.         }
  23.     }
  24. <br>
复制代码
CommonUserHelper 实现 IUserHelper 接口,假设希望在 Create方法执行前/后写入日志,那就存在这4种业务逻辑:
  ① 执行前写入日志,执行 Create
  ② 执行前写入日志,执行 Create,执行后写入日志
  ③ 执行 Create,执行后写入日志
  ④ 执行 Create
  单一个写日志的需求,就能有4种实现方式,极端情况下,是可以实现 4次 Create 方法;
  如果再加一个数据验证、IP验证、权限验证、异常处理、加入缓存..,那么实现的排列组合方式就更多了,
  无穷尽地加实现、替换类,这显然不是我们希望的。
AOP,Aspect Oriented Programing,是一种编程思维,是对这种缺陷的补充。
 
二、DispatchProxy (动态代理)实现AOP
  1. using System.Reflection;
  2. namespace Cjm.AOP
  3. {
  4.     public class TransformProxy
  5.     {
  6.         public static T GetDynamicProxy<T>(T instance)  
  7.         {
  8.             // DispatchProxy 是system.Reflection封装的类
  9.             // 用以创建实现接口T的代理类CustomProxy的实例
  10.             dynamic obj = DispatchProxy.Create<T, CustomProxy<T>>();
  11.             obj.Instance = instance;
  12.             return (T)obj;
  13.         }
  14.     }
  15.     // DispatchProxy 是抽象类,
  16.     // 实现该类的实例,实例方法执行是会跳转到 Invoke 方法中,
  17.     // 以此达到不破坏实际执行的具体逻辑,而又可以在另外的地方实现执行前、执行后
  18.     public class CustomProxy<T> : DispatchProxy
  19.     {
  20.         public T Instance { get; set; }
  21.         protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
  22.         {
  23.             BeforeProcess();
  24.             var relt = targetMethod?.Invoke(Instance, args);
  25.             AfterProcess();
  26.             return relt;
  27.         }
  28.         private void BeforeProcess()
  29.         {
  30.             Console.WriteLine($"This is BegoreProcess.");
  31.         }
  32.         private void AfterProcess()
  33.         {
  34.             Console.WriteLine($"This is AfterProcess.");
  35.         }
  36.     }
  37. }
  38.     // Main
  39.     IUserHelper userHelper3 = new CommonUserHelper();
  40.     userHelper3 = TransformProxy.GetDynamicProxy(userHelper3);
  41.     userHelper3.Create("test0401_B");
复制代码
 
三、通过标记特性,处理多种不同的执行前/执行后方法

  此处借用Castle.Core的封装,
  通过实现 StandardInterceptor以重写 执行前/执行后 逻辑的封装方式,
  我们可以更加聚焦在如何处理多种 执行前/执行后 逻辑的编排上。
  1. using Castle.DynamicProxy;
  2. {
  3.     ProxyGenerator proxy = new ProxyGenerator();
  4.     CustomInterceptor customInterceptor = new CustomInterceptor();
  5.     IUserHelper commonUserHelper = new CommonUserHelper();
  6.     var userHelperProxy = proxy.CreateInterfaceProxyWithTarget<IUserHelper>(commonUserHelper, customInterceptor);
  7.     userHelperProxy.Create("TEST0401_C");
  8. }   
复制代码
  1.     public class CustomInterceptor : StandardInterceptor
  2.     {
  3.         protected override void PreProceed(IInvocation invocation)
  4.         {
  5.             var method = invocation.Method;
  6.             //if (method.IsDefined(typeof(LogBeforeAttribute), true))
  7.             //{
  8.             //    Console.WriteLine("LOG : CustomInterceptor.PreProceed");
  9.             //}
  10.             Action<IInvocation> action = (invocation) => base.PreProceed(invocation);
  11.             // 获取该方法的所有继承BaseAOPAttribute的特性
  12.             var attrs = method.GetCustomAttributes<BaseAOPAttribute>(true);<br>            // 对于 attrs 的排列顺序,可以在特性的实现中增加 int order 属性,在标记特性时写入排序编号
  13.             foreach(var attr in attrs)
  14.             {
  15.                 // 这里是俄罗斯套娃
  16.                 // 相当于 attr3.AOPAction(invocation, attr2.AOPAction(invocation, attr1.AOPAction(invocation, base.PreProceed(invocation))))
  17.                 action = attr.AOPAction(invocation, action);
  18.             }
  19.             action.Invoke(invocation);
  20.         }
  21.         protected override void PerformProceed(IInvocation invocation)
  22.         {
  23.             Console.WriteLine("CustomInterceptor.PerformProceed");
  24.             base.PerformProceed(invocation);
  25.         }
  26.         protected override void PostProceed(IInvocation invocation)
  27.         {
  28.             var method = invocation.Method;
  29.             if (method.IsDefined(typeof(LogAfterAttribute), true))
  30.             {
  31.                 Console.WriteLine("LOG : CustomInterceptor.PostProceed");
  32.             }
  33.             base.PreProceed(invocation);
  34.         }
  35.     }
复制代码
  1.     public class LogBeforeAttribute : Attribute {}
  2.     public class LogAfterAttribute : Attribute {}
  3.     public class CheckIPAttribute : BaseAOPAttribute
  4.     {
  5.         public override Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action)
  6.         {
  7.             return (invocation) => {
  8.                 Console.WriteLine("CheckIP ..");
  9.                 action.Invoke(invocation); <br>            };
  10.         }
  11.     }
  12.     public abstract class BaseAOPAttribute : Attribute
  13.     {
  14.         public abstract Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action);
  15.     }
复制代码
  通过给方法标记特性的方式,达到切面编程的目的(不影响原有实现,而增加实现执行前/执行后的逻辑)
  1.     public interface IUserHelper
  2.     {
  3.         [LogBefore]
  4.         [LogAfter]
  5.         [CheckIP]
  6.         void Create(string name);
  7.         void CreateNoAttri();
  8.     }
复制代码
 

来源:https://www.cnblogs.com/carmen-019/archive/2023/04/02/17280096.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具