关于C#源代码生成器修改函数调用、添加参数及功能范围的技术问询
关于C#源代码生成器修改函数调用、添加参数及功能范围的技术问询
嘿,这个问题问到点子上了,我来帮你理清楚:
首先明确:源生成器不能直接修改现有代码
C#的源生成器(Source Generators)从设计逻辑上就只能做「增量生成新代码」的事儿——它可以读取你写好的代码、分析语法树和语义模型,但绝对碰不了你已经写好的代码(比如你原来的FunctionA(1+2, a+b);调用是不会被直接修改的),只能生成新的.cs文件加入编译流程。
实现你需求的替代方案:生成包装方法
虽然不能改现有调用,但咱们可以曲线救国:用源生成器生成一个包装函数,让这个包装函数自动帮你补上表达式的字符串形式参数,之后你调用这个生成的包装函数就行。举个实际的例子:
假设你原来的方法定义是这样的:
public class MyClass { public void FunctionA(params object[] args) { // 原方法的业务逻辑 } }
源生成器可以分析这个方法的定义,自动生成一个包装方法(比如同名或者叫FunctionAWithExprs),大致是这个样子:
public static class MyClassExtensions { public static void FunctionAWithExprs(this MyClass instance, object arg0, [CallerArgumentExpression("arg0")] string arg0Expr = "", object arg1 = null, [CallerArgumentExpression("arg1")] string arg1Expr = "") { // 把原参数和对应的表达式字符串一起传给原方法 instance.FunctionA(arg0, arg1, arg0Expr, arg1Expr); } }
如果是params这种可变数量的参数,源生成器还能根据调用点的参数个数,动态生成适配不同参数数量的包装方法,或者通过语法树分析直接捕获每个参数的表达式文本(比如把1+2转成字符串"1+2"),再拼到调用参数里。
顺便提一句:你要的效果其实和CallerArgumentExpression属性高度重合
如果你的场景没那么复杂,其实不用源生成器也能实现需求——C# 10引入的CallerArgumentExpressionAttribute就是干这个的:它能自动把你传入参数的表达式文本作为字符串参数传入方法。比如直接修改原方法:
public void FunctionA( object arg0, [CallerArgumentExpression("arg0")] string arg0Expr = "", object arg1 = null, [CallerArgumentExpression("arg1")] string arg1Expr = "") { // 这里你既能拿到计算后的arg0、arg1,也能拿到它们的表达式文本arg0Expr、arg1Expr }
这时候你调用FunctionA(1+2, a+b);,CLR会自动把"1+2"和"a+b"作为后面的参数传进来,完全不用手动写。当然,要是你必须用params可变参数,那源生成器的包装方案会更灵活。
最后再总结下核心点:
- 源生成器不能修改现有代码,只能生成新代码
- 简单场景直接用
CallerArgumentExpression属性更省心 - 复杂可变参数场景,用源生成器生成包装方法来自动补全表达式字符串参数
备注:内容来源于stack exchange,提问作者Igor
相关产品推荐
相关产品推荐

