Microsoft 的下一代编译器项目可如何改进您的代码2014-03-09 MSDN Jason Bock我相信,每个开发人员都希望写出优质的代码。不会有人希望所创建的系统错误百出、不可 维护、需要没完没了地添加功能或解决问题。我曾经参与过一些项目,感觉如同总是处于混 乱状态,毫无乐趣可言。因方法不一致而导致难以理解基本代码,从而浪费了很多时间。我 希望在所从事的项目中,层次经过良好的定义、单元测试丰富充足并且生成服务器持续运行 以确保所有情况正常。此类项目通常会制订由开发人员严格遵守的一组准则和标准。我已见过有团队制订了此类准则。可能由于已将某些方法视为有疑问,因此开发人员应避免 在其代码中调用这些方法。或者,他们可能要确保代码在某些情况下遵循相同的模式。例如 ,项目中的开发人员可能会同意如下准则:任何人都不应使用当地 DateTime 值。所有 DateTime 值都应采用协调世界时 (UTC)。应避免使用在值类型上找到的 Parse 方法(如 int.Parse);应改用 int.TryParse。所创建的所有实体类都应支持等同性,即都应重写 Equals 和 GetHashCode 并实现 == 和 != 运算符以及 IEquatable<T> 接口。我确信您已在某个标准文档中看到过类似的规则。达成一致是件好事情,如果每个人都遵 循同一做法,那么维护代码就会变得更轻松。其中的窍门在于用一种可重用、有效的方式向 团队中的所有开发人员快速地传达这些知识。代码审阅是一种发现潜在问题的方式。 旁观者清,对于给定实现视角新颖的人员经常能发现原作者意识不到的问题。让另一方审阅 您的开发工作可能大有裨益,在审阅者不熟悉此项工作时尤为如此。但是,仍然很容易在开 发过程中忽视一些问题。此外,代码审阅耗时漫长 - 开发人员不得不花费数小时审阅代码并 与其他开发人员开会,交流双方发现的问题。我需要这个过程更加快捷。我希望在出错后尽 可能快地得知。尽快发现故障从长远来看可节省时间和资金。Visual Studio 中有多 种工具(如代码分析)可分析您的代码并向您通知潜在的问题。代码分析有许多预定义规则 ,可揭示未销毁对象或未使用方法参数等情况。遗憾的是,直到编译完毕后,代码分析才运 行其规则,而这可不够快!我希望根据我的标准在键入的新代码中出错时尽快了解这一情况 。尽可能快地发现故障是件好事情。既可节省时间(并因此节省资金),又可避免交付将来 可能会导致无数问题的代码。为此,我需要能够将我的规则编为代码,以使这些规则在我键 入时得以执行,而这正是 Microsoft“Roslyn”CTP 发挥的作用。
Microsoft “Roslyn”是什么?
.NET 开发人员可用于分析其代码的最佳工具之一就是编译器。 它了解如何从语法上将代码分析成各种标记,然后根据这些标记在代码中的位置将其变为有 意义的内容。为此,编译器以其输出的形式将一个程序集发送到磁盘。可在编译管道中搜集 到许多来之不易的知识,而您乐于能够使用这些知识,但是,唉,在 .NET 环境中做不到这 一点,因为 C# 和 Visual Basic 编译器不提供 API 供您访问。Roslyn 使这一情况得到改 观。Roslyn 是一组编译器 API,通过它可靠完整地访问编译器经历的每个阶段。图 1 是 Roslyn 当前在编译器进程中提供的不同阶段的图。

图 1:Roslyn 编译器管道尽管 Roslyn 仍为 CTP 模式(本文中使用的是 2012 年 9 月版),但还 是值得花时间研究其程序集中提供的功能以及了解通过 Roslyn 可做到的事情。首先最好着 眼于其脚本功能。通过 Roslyn,现在可为 C# 和 Visual Basic 代码编写脚本。即 Roslyn 中提供一个脚本引擎,可向该引擎中输入代码段。通过 ScriptEngine 类处理此功能。以下 是一个示例,其中演示此引擎可怎样返回当前的 DateTime 值:
class Program{static void Main(string[] args){var engine = new ScriptEngine();engine.ImportNamespace("System");var session = engine.CreateSession();Console.Out.WriteLine(session.Execute<string>("DateTime.Now.ToString();"));}}
在这段代码中,引擎创建并导入 System 命名空间,因此 Roslyn 将可分析出 DateTime 的含义。创建会话后,它只需调用 Execute,然后 Roslyn 将分析给定的代码。如 果它可正确地分析这段代码,则它将运行这段代码并返回结果。使 C# 成为一种脚本语言是一个强大的概念。虽然 Roslyn 仍处于 CTP 模式,但人们使 用其少量功能即创造出令人惊叹的项目和框架,如 scriptcs (scriptcs.net)。不过,我认为 Roslyn 真正的亮点在于 可创建 Visual Studio 扩展以在编写代码时告知问题。在前一代码段中,我使用了 DateTime.Now。如果我所从事的项目实施了我在本文开头以项目符号列出的第一点,那么我 将违反该标准。以后我将探讨可怎样使用 Roslyn 实施这项规则。但在我这样做之前,我将 介绍编译的第一个阶段: 分析代码以获得标记。
语法树
当 Roslyn 分析一行代码后,它返回一个不可变的语法树。此树包含有关给定代码的任何 信息,包括空格和制表符等细枝末节。即使这段代码有错,代码树仍将尽可能尝试向您提供 尽可能多的信息。这固然很好,但您是否明白相关信息在树中何处?当前,有关 Roslyn 的文档还很少,由 于它仍处于 CTP,这一点可以理解。可使用 Roslyn 论坛张贴问题 (bit.ly/16qNf7w),或在 Twitter 上的推文中使用 #RoslynCTP 标签。在安装文件时,还有一个名为 SyntaxVisualizerExtension 的示例,它 是 Visual Studio 的一个扩展。在 IDE 中键入代码时,可视化工具自动随树的当前版本一 起更新。要搞清您在寻找什么以及如何在树中导航,此工具不可或缺。在对 DateTime 类使用 .Now 时,我搞清了我需要找到 MemberAccessExpression(或者更精确地说,需要找到 基于 MemberAccessExpressionSyntax 的对象),其中最后一个 IdentifierName 值等 于 Now。当然,这适用于输入“var now = DateTime.Now;”的简单情况,而您可能会在 DateTime 前面放置“System.”,或使用“using DT = System.DateTime;”;此外,系统中 的其他类中可能有一个名为 Now 的属性。必须正确处理所有这些情况。