当前位置: 首页 > news >正文

C# DotNetCore AOP简单实现

背景

实际开发中业务和日志尽量不要相互干扰嵌套,否则很难维护和调试。

示例

using System.Reflection;namespace CSharpLearn
{internal class Program{static void Main(){int age = 25;string name = "bingling";Person person = new(age, name);Console.WriteLine("====================不使用AOP====================");person.DisplayMessage();Console.WriteLine();person.DisplayMessage("name");Console.WriteLine("====================不使用AOP====================");Console.WriteLine();/*============================代理对象============================*/PersonProxyDynamic<Person> personProxyDynamic = new();personProxyDynamic.Before += (methodInfo) =>{List<string> pt = new();foreach (ParameterInfo? parameterInfo in methodInfo.GetParameters()){if (parameterInfo.ParameterType.FullName != null){pt.Add(parameterInfo.ParameterType.FullName);}}Console.WriteLine($"准备执行{methodInfo.Name}({string.Join(",", pt)})");};personProxyDynamic.After += (methodInfo) =>{Console.WriteLine($"执行{methodInfo.Name}完毕");};/*============================代理对象============================*/Console.WriteLine("====================使用了AOP====================");personProxyDynamic.Excute(person, "DisplayMessage", new object[] { "name" });Console.WriteLine();personProxyDynamic.Excute(person, "DisplayMessage", null);Console.WriteLine();personProxyDynamic.Excute(person, "DisplayMessage", new object[] { 123 });Console.WriteLine();Console.WriteLine("====================使用了AOP====================");}}/// <summary>/// 人物类/// </summary>public class Person{/// <summary>/// 姓名/// </summary>private readonly string name;/// <summary>/// 年龄/// </summary>private readonly int age;public Person(int age, string name){this.age = age;this.name = name;}/// <summary>/// 打印姓名和年龄/// </summary>public void DisplayMessage(){Console.WriteLine($"{{'age':{age},'name':'{name}'}}");}/// <summary>/// 根据需要打印姓名或年龄/// </summary>/// <param name="type">传入name或age</param>public void DisplayMessage(string type){switch (type){case "name":Console.WriteLine($"{{'name':'{name}'}}");break;case "age":Console.WriteLine($"{{'age':'{age}'}}");break;}}}/// <summary>/// 代理类/// </summary>/// <typeparam name="T">泛型T</typeparam>public class PersonProxyDynamic<T>{/// <summary>/// 执行方法前/// </summary>public Action<MethodInfo>? Before { get; set; }/// <summary>/// 执行方法后/// </summary>public Action<MethodInfo>? After { set; get; }/// <summary>/// 代理执行某个对象的某个方法/// </summary>/// <param name="t">被代理的对象</param>/// <param name="method">被执行的方法</param>/// <param name="args">被执行方法的参数列表</param>public void Excute(T t, string method, params object[]? args){//获取被代理对象的所有名字为传入method的方法MethodInfo[]? methodInfos = typeof(T).GetMethods().Where(item => item.Name == method).ToArray();//没有此名字的方法if (methodInfos == null || methodInfos.Length == 0 || methodInfos.FirstOrDefault(item => item == null) != null){Console.WriteLine($"{t}对象没有{method}方法");return;}//存在此名字的方法,注意区分是否为重载的方法foreach (MethodInfo methodInfo in methodInfos){//方法传参列表是否和args每个元素的类型一一对应bool flag = true;//无参方法,传入null或长度为0的参数列表都可以if (methodInfo.GetParameters().Length == 0 && (args == null || args.Length == 0)){}//有参方法,两者传参长度需要一致、且传入的参数类型等于方法的参数类型或者隶属于其子类else if (methodInfo.GetParameters().Length == args?.Length){for (int i = 0; i < methodInfo.GetParameters().Length; i++){Type type1 = methodInfo.GetParameters()[i].ParameterType;Type type2 = args[i].GetType();//参数列表类型不一致,且传入的参数类型不隶属于签名的参数类型if (type1 != type2 && !type2.IsSubclassOf(type1)){flag = false;break;}}}//有参方法,长度不一致else{flag = false;}//命中用户想调用的方法if (flag){Before?.Invoke(methodInfo);methodInfo.Invoke(t, args);After?.Invoke(methodInfo);return;}}Console.WriteLine("未找到您要调用的方法");}}
}

 运行结果

解析

业务中有一个Person类,其业务为调用Person实例的DisplayMessage方法打印该person对象的个人信息。

PersonProxyDynamic类为其动态代理类,我们在给其对象添加前置后置处理函数后,即可对person对象的所有方法进行代理,这样我们就可以在原本使用person对象方法的地方,替换成动态代理类的Execute方法,保证的原有的person代码不变,业务逻辑干净纯粹。

此示例仅供参考,由于使用了反射,生产环境若是对性能具备高要求,切勿轻易使用!!!

http://www.lryc.cn/news/261981.html

相关文章:

  • 19.Tomcat搭建
  • HarmonyOS云开发基础认证考试满分答案(100分)【全网最全-不断更新】【鸿蒙专栏-29】
  • Unity项目里Log系统该怎么设计
  • 设计模式-状态(State)模式
  • oracle怎么存放json好
  • 【计算机网络】—— 详解码元,传输速率的计算|网络奇缘系列|计算机网络
  • [ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证
  • 计算机网络:网络层(无分类编址CIDR、计算题讲解)
  • Learning Semantic-Aware Knowledge Guidance forLow-Light Image Enhancement
  • 关于嵌入式开发的一些信息汇总:开发模型以及自托管开发(二)
  • 【JavaEE】多线程案例 - 定时器
  • 网络小测------
  • 基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里
  • 04-Nacos中负载均衡规则的配置
  • Kotlin 中的 `use` 关键字:优化资源管理(避免忘记inputStream.close() ?)
  • 时序预测 | Python实现GRU-XGBoost组合模型电力需求预测
  • 扁平化菜单功能制作
  • 网络基础——路由协议及ensp操作
  • Python-折线图可视化
  • C++类与对象 (上)
  • no module named ‘xxx‘
  • Go实现MapReduce
  • Axure的交互样式和情形
  • Mybatis在新增某个数据后,如何获取新增数据的id
  • 12.4~12.14概率论复习与相应理解(学习、复习、备考概率论,这一篇就够了)
  • 关于多重背包的笔记
  • 如何使用 Java 的反射
  • PLC-Recorder V3 修改服务器和客户端通讯端口的方法
  • libevent服务GET/POST的简单使用
  • MySQL 系列:注意 ORDER 和 LIMIT 联合使用的陷阱