不清楚你在做什么,但似乎很清楚的是你有一些基线代码,并且基于它的一些属性,你想生成更多代码。
所以这里的关键问题是,在给定基线代码的情况下,如何提取有趣的属性,以及如何从这些属性生成代码?
反射是一种将运行(至少是加载)代码的属性提取到与反射用户代码相同的执行环境中的方法。反射的问题在于它只提供了一组非常有限的属性,通常是类、方法的列表,或者可能是参数的名称。如果您想要做的所有代码生成都可以用它来完成,那么反射似乎就好了。但是如果你想要关于代码的更详细的属性,反射不会削减它。
事实上,可以从中提取真正任意代码属性的唯一工件是作为字符串的源代码(你怎么能回答,是加法运算符和变量中间的 T 之间的字符数名称是质数?)。实际上,您可以从字符串中获得的属性通常不是很有帮助(请参阅我刚刚给出的示例:)。
编译器人员在过去 60 年中一直在研究如何提取有趣的程序属性,而如果你忽略他们在这半个世纪中学到的东西,那你就是个彻头彻尾的白痴。
他们已经确定了一些相对标准的“编译器数据结构”:抽象语法树 (AST)、符号表 (ST)、控制流图 (CFG)、数据流事实 (DFF)、程序三元组、ponter 分析, 等等。
如果你想分析或生成代码,最好的办法是先将它处理成这样的标准编译器数据结构,然后再完成这项工作。如果您有 AST,则可以回答有关使用哪些运算符和操作数的各种问题。如果你有 ST,你可以回答关于 where-defined、where-visible 和 what-type 的问题。如果您有 CFG,您可以回答有关“this-before-that”、“语句 X 依赖于什么条件”的问题。如果您有 DFF,则可以确定哪些分配会影响代码中某个点的操作。恕我直言,反射永远不会提供此功能,因为它始终仅限于运行时系统开发人员在运行程序时愿意保留的内容。 (也许有一天他们会保留所有编译器数据结构,但它不会是反射;它最终会成为编译器支持)。
现在,在您确定了感兴趣的属性之后,您会为代码生成做什么?在这里,编译器人员一直专注于机器代码的生成,以至于他们不提供标准答案。这样做的人是程序转换社区 (http://en.wikipedia.org/wiki/Program_transformation)。这里的想法是至少将程序的一种表示形式保留为 AST,并为匹配源代码语法提供特殊支持(通过从感兴趣的代码片段构造模式匹配 AST),并提供“重写”规则,如效果,“当你看到这个模式时,然后在这个条件下用那个模式替换它”。
通过将条件与编译器人员的各种属性提取机制联系起来,您可以相对容易地说出您想要的 50 年经验支持的内容。这样的程序转换系统具有读取源代码的能力,
进行分析和转换,一般是转换后重新生成代码。
对于您的代码生成任务,您需要将基线代码读入 AST,应用分析以确定有趣的属性,使用转换生成新的 AST,然后吐出答案。
要使这样的系统有用,它还必须能够解析和漂亮地打印各种源代码语言,以便 C# 爱好者以外的人也可以享受代码分析和生成的好处。
这些想法都在
DMS Software Reengineering Toolkit。 DMS 可处理 C、C++、C#、Java、COBOL、JavaScript、PHP、Verilog 等多种语言。
(我是 DMS 的架构师,所以我的观点比较偏颇。YMMV)。