C# 实现调用函数,打印日志(通过反射代理、非IOC)

在这里插入图片描述

🎈个人主页:靓仔很忙i
💻B 站主页:👉B站👈
🎉欢迎 👍点赞✍评论⭐收藏
🤗收录专栏:C#
🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步!


需求:对于不方便debug的程序,查看日志是一个特别好的调试方式,但是在.net framework中,想实现面向切面打印日志特别困难。有人可能会想到使用Castle,使用Castle确实ok。但它需要依赖注入,需要框架去托管所有需要AOP的对象,系统中还有很多静态类,想实现这些都类的日志打印,我还需要去包装类库中的所有的静态类。这显然不现实,本文就是为了解决这个问题而写。

解决方案:为此,笔者写了一个Logger类,提供了CallStatic,CallMethod方式分别去调用方法,调用方法的时候,打印日志。调用思路也很简单,直接调用就行,需要调用的方法,通过参数传递即可。废话不多说,直接上干货。

  • 程序需要三个文件
    在这里插入图片描述
    • Logger:日志类
    • MyService: 测试使用的方法
    • Program: 入口
  • Logger文件
    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;

    namespace AutoTemplate.log
    {
        public static class Logger
        {
            public static void CallStatic(Expression<Action> expression)
            {
                var methodInfo = (MethodCallExpression)expression.Body;
                var method = GetMethodInfo(methodInfo);
                var parameters = GetParameters(methodInfo);
                PrintStartLog(method, parameters);
                method.Invoke(null, parameters);
                PrintEndLog(method);
            }
            public static T CallStatic<T>(Expression<Func<T>> expression)
            {
                var methodInfo = (MethodCallExpression)expression.Body;
                var method = GetMethodInfo(methodInfo);
                var parameters = GetParameters(methodInfo);

                PrintStartLog(method, parameters);
                var result = (T)method.Invoke(null, parameters);
                PrintEndLog(method);
                return result;
            }

            public static void CallMethod<T>(this T instance, Expression<Action<T>> expression)
            {
                var methodInfo = (MethodCallExpression)expression.Body;
                var method = GetMethodInfo(methodInfo);
                var parameters = GetParameters(methodInfo);

                PrintStartLog(method, parameters);
                method.Invoke(instance, parameters);
                PrintEndLog(method);
            }

            public static TResult CallMethod<T, TResult>(this T instance, Expression<Func<T, TResult>> expression)
            {
                var methodInfo = (MethodCallExpression)expression.Body;
                var method = GetMethodInfo(methodInfo);
                var parameters = GetParameters(methodInfo);

                PrintStartLog(method, parameters);
                var result = (TResult)method.Invoke(instance, parameters);
                PrintEndLog(method);

                return result;
            }

            private static MethodInfo GetMethodInfo(MethodCallExpression methodCall)
            {
                return methodCall.Method;
            }

            private static object[] GetParameters(MethodCallExpression methodCall)
            {
                object[] parameters = methodCall.Arguments.Count > 0
                   ? methodCall.Arguments.Select(arg => Expression.Lambda(arg).Compile().DynamicInvoke()).ToArray()
                   : Array.Empty<object>();
                return parameters;
            }

            private static void PrintStartLog(MethodInfo method, object[] parameters) {
                Console.WriteLine($"==========================================");
                Console.WriteLine($"[Log Start]开始调用方法: {method.Name}({string.Join(", ", parameters)})");
            }

            private static void PrintEndLog(MethodInfo method)
            {
                Console.WriteLine($"[Log End]方法调用成功: {method.Name}");
            }
        }
    }
  • MyService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoTemplate
{
    public class MyService
    {
        public static void NoArgNoResultStaticMethod()
        {
            Console.WriteLine("静态方法:无参无返回值");
        }

        public static void OneArgStaticMethod(string a)
        {
            Console.WriteLine($"静态方法:一个参数无返回值,参数:{a}");
        }

        public static string ResultStaticMethod()
        {
            Console.WriteLine($"静态方法:无参数有返回值,返回值:hello");
            return "这是ResultStaticMethod返回值";
        }

        public void NoArgNoResultMethod()
        {
            Console.WriteLine("方法:无参无返回值");
        }

        public void OneArgMethod(string aaa)
        {
            Console.WriteLine($"方法:一个参数无返回值,参数:{aaa}");
        }

        public int ReturnMethod()
        {
            Console.WriteLine($"方法:无参一个返回值");
            return 0;
        }

        public string OneArgReturnMethod(string e)
        {
            Console.WriteLine($"方法:一个参数一个返回值,参数:{e}");
            return "这是OneArgReturnMethod返回值";
        }

        public string ThreeArgOneResultMethod(string e,float f,int g)
        {
            Console.WriteLine($"方法:三个参数一个返回值,参数:{e},{f},{g}");
            return "这是ThreeArgOneResultMethod返回值";
        }
    }
}

  • Program
using AutoTemplate.log;
using FlaUI.UIA3;
using PATool.Core.Automation;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace AutoTemplate
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //静态方法调用
            Logger.CallStatic(() => MyService.NoArgNoResultStaticMethod());
            Logger.CallStatic(() => MyService.OneArgStaticMethod("abc"));
            var staticRes= Logger.CallStatic(() => MyService.ResultStaticMethod());
            var processRes = Logger.CallStatic(() => Process.Start("notepad++"));

            //对象方法调用
            var myService = new MyService();
            myService.CallMethod(s => s.NoArgNoResultMethod());
            myService.CallMethod(s => s.OneArgMethod("hello"));
            var res1=myService.CallMethod(s => s.ReturnMethod());
            var res2=myService.CallMethod(s => s.OneArgReturnMethod("xlwang"));
            var res3 = myService.CallMethod(s => s.ThreeArgOneResultMethod("xlwang",1.2f,5));

        }
    }
}
  • 运行结果
    在这里插入图片描述

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

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

相关文章

常用代码整理

字符串操作相关函数的实现 gets puts strlen strcat strncat strcpy strncpy strcmp strncmp memcpy 内存大小端判断 类型强制转换 联合 排序 选择排序 冒泡排序 插入排序 快速排序 先选一个基准值&#xff0c;通过双指针扫描并交换元素将数组划分为两部分&#xff0c;左…

Go程序的一生——Go如何跑起来的?

引入编译链接概述 编译过程 词法分析语法分析语义分析中间代码生成目标代码生成与优化链接过程Go 程序启动GoRoot 和 GoPathGo 命令详解 go buildgo installgo run总结参考资料 引入 我们从一个 Hello World 的例子开始&#xff1a; package mainimport "fmt"func…

Spring Boot框架下JavaWeb在线考试系统的创新实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

基于机器学习的心脏病风险评估预测系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 心脏病是全球范围内导致死亡的主要原因之一。早期识别和预防心脏病对于减少发病率和死亡率至关重要。传统的风险评估方法通常依赖于医生的经验和简单的风险因子计算&#xff0c;这种方法存在一定的…

QT的文件操作类 QFile

QFile 是 Qt 框架中用于文件处理的一个类。它提供了读取和写入文件的功能&#xff0c;支持文本和二进制文 件。 QFile 继承自 QIODevice &#xff0c;因此它可以像其他IO设备一样使用。 主要功能 文件读写&#xff1a; QFile 支持打开文件进行读取或写入操作文件信息&#x…

SCI论文快速排版:word模板一键复制样式和格式【重制版】

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间SCI论文快速排版&#xff1a;word模板一键复制样式和格式&#xff1a;视频操作视频重置版2【推荐】 SCI论文快速排版&#xff1a;word模板一键复制样式和格式【重制版】 模板与普通文档的区别 为了让读者更好地…

VHDL基本结构和逻辑示例

VHDL基本结构和逻辑示例 1.VHDL的基本结构 VHDL的基本结构包含了三段&#xff1a; -- library and package -- entity -- architecturelibrary and package&#xff1a;相关库和软件包&#xff08;相当与c语言的头文件&#xff09; entity&#xff1a;实体&#xff08;描述输…

redis IO多路复用机制

目录 一、五种 I/O 模型 1.阻塞IO&#xff08;Blocking IO&#xff09; 2.非阻塞IO&#xff08;Nonblocking IO&#xff09; 3.IO多路复用&#xff08;IO Multiplexing&#xff09; 通知的方式 select模式 poll模式 epoll模式 4.信号驱动IO&#xff08;Signal Driven …

QT 实现按钮多样化

1.界面实现效果 以下是具体的项目需要用到的效果展示&#xff0c;可以根据需要&#xff0c;实例化想要的按钮。 2.简介 原理&#xff1a;使用Qt的QPropertyAnimation动画类&#xff0c;这里简单来说就是切换两个按钮样式。 请看以下结构体&#xff1a; #define MAX_LINE_C…

系统架构设计师⑧:软件工程-软件开发方法与模型

系统架构设计师⑧&#xff1a;软件工程-软件开发方法与模型 软件开发方法 常用的软件开发方法主要分为3类&#xff1a; 结构化法&#xff08;比如C语言开发-面向过程&#xff09;&#xff0c; 面向对象法&#xff08;比如C或者JAVA开发-面向对象&#xff09;&#xff0c; 面向…

Nodejs和C#使用ECDH算法交换秘钥

转载于&#xff1a;https://bkssl.com/document/nodejs-csharp-ecdh.html nodejs的ECDH算法在进行computeSecret的时候不会自动进行HASH运算&#xff0c;但C#的ECDH算法必须指定HASH算法。 两边算法必须使用相同的椭圆曲线和Hash算法&#xff0c;例如下面用例都是用的SHA256。…

Matlab|用于平抑可再生能源功率波动的储能电站建模及评价

目录 主要内容 模型研究 1.目标函数 2.约束条件 部分代码 结果一览 1.储能平抑风电功率 2.储能平抑风电和光伏功率 下载链接 主要内容 程序参考文献《用于平抑可再生能源功率波动的储能电站建模及评价》&#xff0c;针对风电和光伏分布式能源出力波动的问…

题目:连续子序列

解题思路&#xff1a; 首先&#xff0c;不能使用暴力枚举&#xff0c;时间为O(n2)&#xff0c;超时。以下为正确做法&#xff1a; 假设找到一段区间&#xff08;其和>m&#xff09;&#xff0c;如上图黄色部分&#xff0c;那么该区间加上i后面的元素形成的新区间和都>m&a…

opencv学习:CascadeClassifier和detectMultiScale算法进行人脸识别

CascadeClassifier CascadeClassifier 是 OpenCV 提供的一个用于对象检测的类&#xff0c;它基于Haar特征和AdaBoost算法。它能够识别图像中的特定对象&#xff0c;比如人脸、眼睛、微笑等。CascadeClassifier 需要一个预训练的XML分类器文件&#xff0c;该文件包含了用于检测…

CodeActAgent :Executable Code Actions Elicit Better LLM Agents解读

论文地址 https://arxiv.org/pdf/2402.01030.pdf 项目地址 https://github.com/svjack/CodeActAgent-Gradio/blob/main/README.md 代码智能体的优势 选择代码智能体有以下几个关键原因&#xff0c;它们相较于使用类似JSON的字典输出具有显著优势&#xff1a; 1. 代码的高…

Spring Boot 应用开发:入门与实战

Spring Boot 应用开发&#xff1a;入门与实战 引言 Spring Boot 是 Spring 框架的一个子项目&#xff0c;旨在简化 Spring 应用的配置和开发。它通过自动配置和嵌入式服务器&#xff0c;极大地简化了 Java 企业级应用的开发。本文将详细介绍 Spring Boot 的核心概念&#xff…

【SPIE独立出版】第四届计算机、信息工程与电子材料国际学术会议 (CTIEEM 2024,2024年11月15-17日 )

第四届计算机、信息工程与电子材料国际学术会议 (CTIEEM 2024) The 4th International Conference on Computer Technology, Information Engineering and Electron Materials 会议官网&#xff1a;www.ctieem.org The 4th International Conference on Computer Technology,…

【bug】paddleocr draw_ocr_box_txt ValueError: incorrect coordinate type

【bug】paddleocr draw_ocr_box_txt ValueError: incorrect coordinate type 环境 python 3.10.15pillow 10.4.0 paddleocr 2.8.1错误详情 错误文本 Traceback (most recent call last):....draw_left.polygon(box, fillcolor)ValueError: inco…

浏览器内置文字转语音,播报功能Web Speech API - SpeechSynthesisUtterance

SpeechSynthesisUtterance: 让网页说话的艺术 在现代Web开发中&#xff0c;让网页具有语音功能可以极大提升用户体验&#xff0c;特别是对于视障用户或需要多任务处理的场景。SpeechSynthesisUtterance 是 Web Speech API 中的一个接口&#xff0c;它允许开发者创建一个语音合…

穷举vs暴搜vs深搜vs回溯vs剪枝(一)

文章目录 全排列子集找出所有子集的异或总和再求和全排列 II电话号码的字母组合 全排列 题目&#xff1a;全排列 思路 通过深度优先搜索的方式&#xff0c;不断枚举每个数在当前位置的可能性&#xff0c;然后回溯到上一个状态&#xff0c;直到枚举完所有可能性得到正确的结果 r…