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代码不变,业务逻辑干净纯粹。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/253325.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java CPU使用率高排除方法

CPU使用率高排除方法 查询CPU使用率高的进程查询线程CPU使用率ps命令方式top 命令方式 查询线程堆栈 jstat 查询gc情况 查询CPU使用率高的进程 ps aux --sort-pcpu | head -10通过ps指令看到pid1799程序CPU使用率47.1%&#xff0c;再看看程序的线程使用情况。 查询线程CPU使用…

【Hive】——DDL(CREATE TABLE)

1 CREATE TABLE 建表语法 2 Hive 数据类型 2.1 原生数据类型 2.2 复杂数据类型 2.3 Hive 隐式转换 2.4 Hive 显式转换 2.5 注意 3 SerDe机制 3.1 读写文件机制 3.2 SerDe相关语法 3.2.1 指定序列化类&#xff08;ROW FORMAT SERDE ‘’&#xff09; 3.2.2 指定分隔符&#xff0…

虚拟网络管理解决方案

随着业务规模的扩大&#xff0c;其网络的规模和复杂性也成比例地扩大&#xff0c;企业级组织和中小型企业需要大规模网络来满足不断增长的业务需求&#xff0c;然而&#xff0c;大规模网络需要大量的物理组件、定期维护和配置&#xff0c;所有这些都是有代价的&#xff0c;因此…

[ACTF2020 新生赛]Include (文件包含漏洞)

打开题目&#xff1a; 就一个tips 看看源码&#xff1a; 奥&#xff0c;fileflag.php 而且再看题目&#xff1a;include 应该是文件包含漏洞&#xff0c;是一道php伪协议题目 -.-PHP伪协议-.-&#xff1a; 我们通过 php://filter 来获取源码&#xff1a; 构造payload: …

runCatching异常捕获onSuccess/onFailure返回函数,Kotlin

runCatching异常捕获onSuccess/onFailure返回函数&#xff0c;Kotlin fun test(a: Int, b: Int) {runCatching {a / b}.onSuccess {println("onSuccess: $it")return ok(it)}.onFailure {println("onFailure: $it")return fail(it)} }fun ok(o: Any) {prin…

【基础算法】前缀和

文章目录 算法介绍什么是前缀和&#xff1f;&#xff1f;前缀和的作用一维数组求解前缀和(Si)二维数组求解前缀项和 示例题目1&#xff1a;acwing795示例题目2&#xff1a;acwing796总结收获 算法介绍 什么是前缀和&#xff1f;&#xff1f; 数组: a[1], a[2], a[3], a[4], a[…

轻量封装WebGPU渲染系统示例<48>- 多种光源的多种组合(源码)

实现方式: 1. 全局的灯光和阴影。 2. 球体和矩形平面使用了相同的材质对象。 3. 通过材质自动关联和组装对应的渲染材质功能节点。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MultiLightsShading2.ts 当前…

人生感悟 | 当前经济形势,给25~35岁的年轻人一点建议

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 这两年经济情况怎么样呢&#xff1f;相信大家都有自己的感觉。 且不说网上看到的“裁员裁到大动脉”“设计院欠薪”等各种新闻。 说自己和家人的亲身经历吧&#xff0c;这两年经历了被拖欠工资、公司缩编、换工作、公…

公众号提高上限怎么操作?

一般可以申请多少个公众号&#xff1f;众所周知&#xff0c;在2013年前后&#xff0c;公众号申请是不限制数量的&#xff0c;后来企业开始限制申请50个&#xff0c;直到2018年的11月tx又发布&#xff0c;其中个人主体可申请公众号由2个调整为1个&#xff0c;企业主体由50个调整…

【基础算法】试除法判定质数(优化)

文章目录 算法优化模板题目代码实现 算法优化模板 bool is_prime(int n){if(n < 2) return false;for(int i 2;i < n / i;i ){ //优化内容if(n % i 0){return false;}}return true; }注意这里的一个总要优化是for循环的终止条件是i<n/i。为什么不是i<n或者i<…

UDP多人聊天室

讲解的是TCP和UDP两种通信方式它们都有着自己的优点和缺点 这两种通讯方式不通的地方就是TCP是一对一通信 UDP是一对多的通信方式 UDP通信 主要的方向是一对多通信方式 UDP通信就是一下子可以通信多个对象&#xff0c;这就是UDP对比TCP的优势&#xff0c;UDP它的原理呢 就是…

Python glob

参考文章&#xff1a; Python 中glob.glob()、glob.iglob&#xff08;&#xff09;的使用-CSDN博客 Python 中glob.glob()的使用 glob.glob(path)的功能&#xff1a; 返回符合path格式的所有文件的路径&#xff0c;以list存储返回。 path的表示方法&#xff1a; 利用匹配符…

uniapp怎么获取微信步数

微信步数获取的背景 微信步数是指用户在微信运动中记录的步数数据。微信提供了开放能力&#xff0c;允许第三方应用获取用户授权后的微信步数数据&#xff0c;以便进行进一步的数据分析和展示。使用时报错&#xff1a;fail api scope is not declared in the privacy agreemen…

雷电4.0.50模拟器Android7.1.2安装xposed框架

官方论坛&#xff1a;https://xdaforums.com/t/official-xposed-for-lollipop-marshmallow-nougat-oreo-v90-beta3-2018-01-29.3034811/ Xposed 有分支 [EdXposed 和 LSPosed] 。 Edxposed框架现在支持android 8.0 - android 9.0 &#xff0c;如果是android 7.0或更早的版本&…

1.3 第一个C程序

一、Dev-C的安装 下载地址&#xff1a;https://sourceforge.net/projects/orwelldevcpp/ 二、Dev-C简单的使用 2.1 首次打开配置 2.2 第一个程序的编辑、编译、运行 三、Hello Word程序讲解 3.1 程序框架 几乎所有的程序都需要这一段代码 3.2 输出 printf("Hello World…

大数据机器学习深度解读ROC曲线:技术解析与实战应用

大数据机器学习深度解读ROC曲线&#xff1a;技术解析与实战应用 一、引言ROC曲线简介 二、ROC曲线的历史背景二战雷达信号检测在医学和机器学习中的应用横跨多个领域的普及 三、数学基础False Positive Rate&#xff08;FPR&#xff09;计算方法 四、Python绘制ROC曲线导入所需…

广受好评的开源基础大模型最全梳理,你最钟意哪一个?

2023 年即将过去。一年以来&#xff0c;各式各样的大模型争相发布。当 OpenAI 和谷歌等科技巨头正在角逐时&#xff0c;另一方「势力」悄然崛起 —— 开源。 开源模型受到的质疑一向不少。它们是否能像专有模型一样优秀&#xff1f;是否能够媲美专有模型的性能&#xff1f; 迄…

全套SpringBoot讲义01

hello&#xff0c;我是小索奇&#xff0c;全套SpringBoot教程~一起来学习叭 文章目录 SpringBoot文档更新日志前言课程内容说明课程前置知识说明 SpringBoot基础篇JC-1.快速上手SpringBootJC-1-1.SpringBoot入门程序制作&#xff08;一&#xff09;JC-1-2.SpringBoot入门程序制…

Unity中URP下的菲涅尔效果实现(URP下的法线和视线向量怎么获取)

文章目录 前言一、实现思路二、实现原理我们可以由下图直观的感受到 N 与 L夹角越小&#xff0c;点积越接近&#xff08;白色&#xff09;1。越趋近90&#xff0c;点积越接近0&#xff08;黑色&#xff09; 三、实现URP下的菲涅尔效果1、我们新建一个Shader&#xff0c;修改为最…

beebox靶场A1 low 命令注入通关教程(上)

一&#xff1a;html注入 get HTML注入&#xff0c;就是当用户进行输入时&#xff0c;服务器没有对用户输入的数据进行过滤或转义&#xff0c;导致所有输入均被返回前端&#xff0c;网页解析器会将这些数据当作html代码进行解析,这就导致一些恶意代码会被正常执行。 首先进行简…