C# DotNetCore AOP简单实现

news2024/11/29 2:44:03

背景

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

示例

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.coloradmin.cn/o/1318375.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Oracle RAC环境下redo log 文件的扩容

环境&#xff1a; 有一个2节点RAC每一个节点2个logfile group每一个group含2个member每一个member的大小为200M 目标&#xff1a;将每一个member的大小有200M扩充到1G。 先来看下redo log的配置&#xff1a; SQL> select * from v$log;GROUP# THREAD# SEQUENCE# …

【SpringBoot零基础入门到项目实战①】解锁现代Java开发之门:深度探究Spring Boot的背景、目标及选择理由

文章目录 引言Spring Boot的背景和目标背景目标 为什么选择Spring Boot1. 简化配置2. 内嵌式容器3. 生态系统支持4. 大量的Starter5. 广泛的社区支持6. 适用于微服务架构7. 丰富的扩展机制 实例演示创建一个简单的Spring Boot应用 拓展与深入学习1. Spring Boot Actuator2. Spr…

深度学习 Day14——P3天气识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…

2023.12.16 关于 分布式系统 基本介绍

目录 单机架构 服务器负载过高问题 解决方法 分布式系统 引入更多的服务器节点 负载均衡 数据库读写分离 引入缓存 数据库分库分表 引入微服务 基本概念 应用&#xff08;Application&#xff09;/ 系统&#xff08;System&#xff09; 模块&#xff08;Modul…

力扣刷题-二叉树-二叉树左叶子之和

404 左叶子之和 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 24 思路 迭代法 迭代法理解…

python学习1补充

大家好&#xff0c;这里是七七&#xff0c;这个专栏是用代码实例来学习的&#xff0c;不是去介绍很多知识的。 话不多说&#xff0c;开始今天的内容 目录 代码1 代码2 代码3 代码4 代码5 学习1的总代码 代码1 groupeddf.groupby(单品编码) result{} groupeddf.groupb…

条款5:了解c++默默编写并调用了哪些函数

如果你不自己声明&#xff0c;编译器会替你声明&#xff08;编译器版本的&#xff09;拷贝构造函数、拷贝赋值运算符和析构函数。此外&#xff0c;如果你没有声明任何构造函数&#xff0c;编译器会为你声明一个默认构造函数。 class Empty{};本质上和写成下面这样是一样的: c…

英文论文降重修改技巧 papergpt

大家好&#xff0c;今天来聊聊英文论文降重修改技巧&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 英文论文降重修改技巧 作为网站编辑&#xff0c;我们经常需要处理大量…

加密的艺术:对称加密的奇妙之处(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

菜鸟学习日记(python)——匿名函数

Python 使用 lambda 来创建匿名函数。 lambda 函数是一种小型、匿名的内联函数&#xff0c;它可以具有任意数量的参数&#xff0c;但只能有一个表达式。 匿名函数的一般格式如下&#xff1a; lambda 参数列表:表达式 表达式用于计算并返回函数结果 lambda 函数通常用于编写…

如何优雅地观察 Vue.js 3 中 localStorage 的变化?

为什么要这样做&#xff1f; 原生 localStorage 只能监听同源跨不同页面的变化。然而&#xff0c;对于单页面应用程序来说&#xff0c;这种方式并不实用。因此&#xff0c;我打算创建一个自定义钩子来监视 localStorage 中的变化。 方法 我们需要重写 localStorage 下的所有…

相机基础概念介绍

一.概念 Camera的成像原理 景物通过镜头&#xff08;LENS&#xff09;生成的光学图像投射到图像传感器(Sensor)表面上&#xff0c;然后转为模拟的电信号&#xff0c;经过 A/D&#xff08;模数转换&#xff09;转换后变为数字图像信号&#xff0c;再送到数字信号处理芯片&…

虚拟机下Ubuntu上网设置

文章目录 一、虚拟机上网的两种方式1.1 NAT模式&#xff08;Network Address Translation&#xff09;1.2 桥接模式&#xff08;Bridge Mode&#xff09;1.3 简介 二、实际配置2.1 NAT模式配置2.2 桥接模式配置 之前跟着博客配了好几个也没用&#xff0c;后来自己慢慢模式实践测…

机器学习---模型评估

1、混淆矩阵 对以上混淆矩阵的解释&#xff1a; P&#xff1a;样本数据中的正例数。 N&#xff1a;样本数据中的负例数。 Y&#xff1a;通过模型预测出来的正例数。 N&#xff1a;通过模型预测出来的负例数。 True Positives:真阳性&#xff0c;表示实际是正样本预测成正样…

波奇学Linux:进程终止

写时拷贝底层原理图 子进程谁先运行&#xff0c;由调度器决定 进程退出场景 代码运行完毕&#xff0c;结果正确&#xff1a;有返回值&#xff0c;返回0 代码运行完毕&#xff0c;结果不正确&#xff1a;有返回值&#xff0c;返回非0 代码异常终止。没有返回值 return 0的…

小姐姐跳舞,AI 视频生成太酷了

大家好&#xff0c;我是章北海 最近AI视频领域的研究进展神速&#xff0c;看得眼花缭乱。 这里老章就把最近几天看过印象深刻的四个项目介绍给大家&#xff0c;同时附上项目相关简介、论文、代码等资料&#xff0c;感兴趣的同学可以深度研究一下。 《SMPLer-X:放大表达性人体…

设计模式(2)--对象创建(5)--单件

1. 意图 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 2. 一种角色 单件(Singleton) 3. 优点 3.1 对唯一实例的受控访问 3.2 缩小名空间(对全局变量的改进) 3.3 允许对操作和表示精化(可以有子类) 3.4 允许可变数目的实例 3.5 比类操作更灵活 4. 缺点…

mipi dsi协议DBI/DPI接口

MIPI dsi协议中的DBI/DPI接口主要用于主机和display设备之间的数据传输&#xff0c;说的更通俗一点就是DSI RX控制器和实际的显示面板之间的接口&#xff1b;dsi 协议spec中对DBI/DPI有描述&#xff1a; DSI协议中对DBI 接口模式命名为command mode operation&#xff0c;对DP…

[NCTF2019]Fake XML cookbook1

提示 xml注入 一般遇到像登录页之类的就因该想到sql注入、弱口令或者xml等 随便输入抓包 这里明显就是xml注入 这里我们来简单了解一下xml注入 这里是普通的xml注入 xml注入其实和sql注入类似&#xff0c;利用了xml的解析机制如果系统没有将‘<’‘>’进行转义&#xff0…

《点云处理》 提取点云内点和外点

前言 关于内点&#xff08;inliers&#xff09;和外点&#xff08;outliers&#xff09;在点云处理方向上是个非常常见的名词。有时候&#xff0c;内点也会被称之为有效点&#xff0c;而外点会被称之为无效点。所谓有效和无效都是相对而言的&#xff0c;无效不一定是真的没有意…