如何在C#项目中实现获取指定方法所有调用参数的函数?
问题需求
需要实现一个函数,获取项目中MethodA(string a)所有调用的参数值。比如存在以下调用:
MethodA("1"); MethodA("2");
调用GetAllMethodArguments("MethodA")应返回["1", "2"]。尝试用反射实现,但没能成功。
为什么反射搞不定这事
反射的核心是读取程序集的元数据,比如方法的名称、参数类型、返回值类型这些定义,但它没法追踪方法调用时的动态参数值:
- 反射没有能力回溯已经执行过的调用的参数
- 也没法主动监听方法的所有调用并捕获参数
简单说,反射管的是"方法是什么样的",不是"方法被怎么调用的"。
两种可行的实现方案
方案1:在目标方法内部埋点记录
这是最直接的运行时方案,修改MethodA,每次调用时把参数存到全局集合里,GetAllMethodArguments直接读取这个集合:
// 全局存储MethodA的调用参数,用静态集合保证生命周期一致 private static readonly List<string> _methodAArgs = new List<string>(); public static void MethodA(string a) { // 先记录参数 _methodAArgs.Add(a); // 原来的方法逻辑 // ... } public static List<string> GetAllMethodArguments(string methodName) { if (methodName == nameof(MethodA)) { // 返回副本,避免外部修改内部集合 return new List<string>(_methodAArgs); } return new List<string>(); }
方案2:静态代码分析(编译期提取)
如果不能修改MethodA的代码,可以用.NET的Roslyn编译器API做静态代码分析,遍历项目源码,解析语法树找到所有MethodA的调用,提取字面量参数:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.IO; public static List<string> GetAllMethodArgumentsFromSource(string projectRootPath, string targetMethodName) { var collectedArgs = new List<string>(); // 遍历项目下所有C#源码文件 foreach (var csFile in Directory.EnumerateFiles(projectRootPath, "*.cs", SearchOption.AllDirectories)) { var codeText = File.ReadAllText(csFile); var syntaxTree = CSharpSyntaxTree.ParseText(codeText); var rootNode = syntaxTree.GetRoot(); // 找所有方法调用节点 var invocations = rootNode.DescendantNodes().OfType<InvocationExpressionSyntax>(); foreach (var invocation in invocations) { // 判断是不是目标方法的调用 if (invocation.Expression is IdentifierNameSyntax methodId && methodId.Identifier.Text == targetMethodName) { // 取第一个参数(对应MethodA的string参数) var firstArg = invocation.ArgumentList.Arguments.FirstOrDefault(); if (firstArg?.Expression is LiteralExpressionSyntax stringLiteral && stringLiteral.Kind() == SyntaxKind.StringLiteralExpression) { collectedArgs.Add(stringLiteral.Token.ValueText); } } } } return collectedArgs; }
注意:这个方案只能提取编译期的字符串字面量参数,如果调用时传入的是变量、表达式或者运行时生成的值,是没法拿到实际运行值的,只能拿到代码里的表达式内容。
内容的提问来源于stack exchange,提问作者Ander Xt
相关产品推荐
相关产品推荐

