如何在编译之前修改代码?

Luk*_*sky 47 c# roslyn

使用Roslyn,我想在实际编译之前修改我的C#代码.现在,我只需要:

[MyAnotatedMethod]
public void MyMethod() 
{
    // method-body 
}
Run Code Online (Sandbox Code Playgroud)

并且基于注释,我想在方法的开头和方法的末尾注入一些代码.

我知道PostSharp,但那不是我想要的.

这可能与罗斯林有关吗?如果是的话,你能举个例子吗?

Tam*_*mas 19

这是一种快速而肮脏的方式来做你想做的事.它基于上述评论之一,指向SebbyLive.这只是一个概念证明,我不会尝试在生产中使用它.

基本思想是更改要修改的项目的编译器.这个改变了的编译器将执行代码注入.因此,您需要编写一个新的编译器(AopCompiler.exe)并将其设置为项目中的构建工具.

将AopCompiler.exe设置为构建工具很简单,在项目文件中,您需要添加以下两行:

<CscToolPath>$(SolutionDir)AopCompiler\bin\Debug</CscToolPath>
<CscToolExe>AopCompiler.exe</CscToolExe>
Run Code Online (Sandbox Code Playgroud)

AopCompiler应该是一个简单的控制台应用程序.这也是代码修改和编译.如果您不想修改源代码,只需构建它,那么最简单的方法是自己调用csc.exe:

static void Main(string[] args)
{
  var p = Process.Start(@"C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe", 
            string.Join(" ", args));
  p.WaitForExit();
}
Run Code Online (Sandbox Code Playgroud)

因此,如果你设置到目前为止,你将有一个正常的构建过程,没有编织方面.

在这一点上,如果你看看什么是在args,你会看到有一个文件路径的.RSP文件,它包含了所有的CSC.EXE命令行参数.当然,这些参数也包含所有.CS文件名.因此,您可以解析此.RSP文件并查找所有.CS文件,这些都是编译的一部分.

有了C#文件,可以用Roslyn完成重写.有很多教程CSharpSyntaxRewriter,例如这里这里.您需要编写自定义CSharpSyntaxRewriter,检查给定属性,然后将日志记录添加到找到的方法的开头.将记录添加到每个方法的末尾有点棘手,因为可能有多个退出点.要找到这些,您可以使用控制流分析.内置的Roslyn控制流分析可以准确地为您提供所需的内容,该ExitPoints属性将一组语句保存在跳转到该区域外的位置的区域内.

要获得语义模型(然后进行CFG分析),您可以执行以下操作:

public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
    var semanticModel = _compilation.GetSemanticModel(node.SyntaxTree);
    // semanticModel.AnalyzeControlFlow(node.Block)
    return node;
}
Run Code Online (Sandbox Code Playgroud)

最后,为了处理每个输入文件,你的AopCompiler,你只需要Visit在树的根上调用你的重写器方法.这将生成修改后的树,您可以将其写入文件.(您可以修改原始文件,或将结果写入新文件,并相应地更改.RSP文件.)

很抱歉没有提供完整的解决方案,但我希望,这足以让您入门.


Jer*_*son 8

正如我在评论中指出的那样,它目前无法使用.虽然你可以把东西一起使用AOP显示技术,在这里罗斯林脚本API提供了非常灵活的解决方案.

目前正确的答案是罗斯林团队有一个公开的提案/问题来支持它.感谢.Net Foundation和Microsoft参与开源,您可以在这里阅读有关此功能开发的信息:

https://github.com/dotnet/roslyn/issues/5561