Visual Studio 2015高级编程(第6版)
上QQ阅读APP看书,第一时间看更新

16.3 .NET编译器平台(Roslyn)

对于多数的开发人员而言,编译器的内部运作是一个黑箱。代码行是输入,输出是一个能执行的应用程序。这种级别的理解对于开发人员而言就足够了。然而,作为翻译过程的一部分,编译器构建了大量有关代码结构的信息。它知道变量是什么,在什么地方使用它们。它可以识别谁调用了什么方法。但所有的这些知识和其他知识都仅仅是编译器的范围。

应用这些知识有助于提高效率。IntelliSense就是一个例子;重构是另一个例子。但是,至少在这一点上,编译器收集的知识还没有任何方式可以在一个更广泛的基础上使用。这就是Roslyn出现的原因。

Roslyn的核心使命(这是.NET编译器平台的官方名称)是将编译器拥有的知识开放给第三方应用程序。所以Roslyn不是使用传统的、不透明、输入代码-输出应用程序的模型,而是有一组API,可以用于与代码相关的、工具和应用程序需要的任务。

说实话,大多数开发人员实际上不可能直接使用这些API。然而,有了Roslyn,第三方就可能利用编译器现有的知识。代码分析、重构工具和语言扩展都可以成为.NET生态系统的一部分。

有时仍希望或需要利用Roslyn提供的功能。尽管完整描述Roslyn实现的API超出了本书的范围,但应在高层次上了解Roslyn的功能。只有这样才能激发我们的灵感。

首先要学习存在于现代编译器中的阶段。图16-1说明了从源代码转变为对象代码的过程中经历的不同阶段。

图16-1

第一步是把源代码标志化为原子元素(关键字、符号或其他类型的标识符),然后使用语言的句法语法解析这些标识符。在最后阶段,有一个语法树,这是线性标识符在树结构中的表示。

接下来在声明阶段,分析了语法树,创建了一个符号表。符号表是一个标识符列表和关于类型、范围和任何相关的元数据的详细信息。事实上,这一步的输出是一个分层的符号表。

在绑定阶段,声明阶段的符号匹配语法树中标识的符号。这不仅包括源代码中的变量,而且包含任何函数引用。

最后在发布阶段,通过其他三个阶段收集的所有信息合并起来,生产执行最终应用程序所需的IL代码。

Roslyn提供了许多API,来支持扩展和操纵每个阶段的结果。对于每个API,没有对Visual Studio的依赖。这意味着如果创建使用这些API的工具,就不需要在Visual Studio中部署工具,来使用它们。

16.3.1 编译器API

编译器API提供的对象模型对应于编译器管道中每个不同阶段的对象和输出。此外,它应用于当前进程时,还包含编译器的表示,包括选项、源代码文件和任何引用的程序集。

Roslyn实际上有两个编译器API:一个用于C#,另一个用于Visual Basic。它们的结构类似,但分别建立两个API,可以更好地发挥各个语言的优势。

16.3.2 诊断API

编译器会产生许多不同的诊断信息,作为其工作的一部分,涵盖了从语法和语义到错误和警告的所有信息。通过这个API,可以把用户定义的分析程序插入编译过程。这样就能创建类似于StyleCop和FxCop过去生成的输出 (这两个工具用于评估源代码是否符合一套规则)。

使用诊断API的一个优点是,诸如MSBuild和Visual Studio的工具可以使用编译的外部评估。这些工具使用诊断信息来确定编译是否成功,或是否给编辑器添加波浪线。与诊断API交互操作,自己的规则就可以无缝地集成到开发人员已在使用的工具。

16.3.3 工作区API

工作区API提供了在整个解决方案中执行代码分析和重构的起点。它维护着有关解决方案中所有项目的所有信息。这就允许访问编译器的对象模型,而不需要自己解析文件。

此外,有一组API可用于实现代码的分析和重构。这些API目前用于实现Visual Studio特性,比如Find All References 和Formatting。但是,与Roslyn中的所有API一样,这组API的成功是不依赖Visual Studio的。不管它们是否可以通过Visual Studio使用,工具都是有效的。