Microsoft Roslyn是微軟.NET“編譯器即服務(Compiler as a Service)”的主要產品,它提供了開放的編譯器API,併為原始碼產生、分析和重構提供了新一代的語言物件模型。Anders Hejlsberg在BUILD 2013大會上提到,C# 6.0的編譯器將使用Roslyn實現,這一實現會包含在Visual Studio 2013之後的產品中。根據Anders的描述,C# 6.0的編譯器將採用C#開發,從而告別現有的本機程式碼(native code)的實現方式,“雖然是採用C#來實現C#編譯器,但我想效能至少不會比原來的實現方式差。”
有關Roslyn的內容,可以參考以下連結:
讓我們先睹為快,瞭解一下Roslyn的一個具體應用:提取C#和VB.NET程式碼中的字串常量。
字串常量的提取
先看下面的一段程式碼:
using System; using System.Collections; using System.Linq; using System.Text; namespace HelloWorld { class Program { static void Main(string[] args) { // Output a "greeting" string Console.WriteLine("Hello, World!"); // Output another "say hello" string Console.WriteLine("Hi, nice to meet you!"); } } }
很明顯這段程式碼中有四個字串:greeting、Hello, World!、say hello和Hi, nice to meet you!,或許我們可以通過正規表示式來提取這些字串,但請注意:這些字串中有兩個是在註釋語句中出現的,而不是我們所需要的字串常量。我們只需要得到其中真正用於可執行程式碼的Hello, World!和Hi, nice to meet you!,這如果通過正規表示式來區分還是有一定難度的,而且對於字串中的轉義字元等特殊字元的判斷和提取,正規表示式也略顯麻煩。
現在,讓我們用Roslyn來完成這一工作。首先,開啟Visual Studio 2012/2013,新建一個控制檯程式(Console Application),.NET Framework的版本選用4.5或者4.5.1。然後,在新建的控制檯程式專案上單擊右鍵,選擇Manage NuGet Packages選單項(注意:.NET Framework的版本必須是4.5以上):
在開啟的對話方塊中,搜尋Roslyn,並將Roslyn安裝到專案中:
首先建立一個語法樹的訪問者,它繼承於Roslyn.Compilers.CSharp.SyntaxWalker,用於遍歷訪問C#的語法樹,它的實現如下:
class ExtractStringLiteralVisitor : SyntaxWalker { readonly List<string> literals = new List<string>(); public override void VisitLiteralExpression(LiteralExpressionSyntax node) { if (node.Kind == SyntaxKind.StringLiteralExpression) literals.Add(node.ToString()); base.VisitLiteralExpression(node); } public IEnumerable<string> Literals { get { return literals; } } }
然後,將上面第一段程式碼文字儲存到一個名為source的字串變數中(當然實際應用中也可以從檔案讀入原始碼),並使用SyntaxTree產生語法樹物件,之後使用上面的ExtractStringLiteralVisitor從根部對語法樹進行遍歷。由於重寫的VisitLiteralExpression方法中儲存了被訪問的文字節點,因此,當Visitor完成遍歷之後,即可通過Literals屬性獲得所有的字串常量。
var syntaxTree = SyntaxTree.ParseText(source); var root = syntaxTree.GetRoot(); var visitor = new ExtractStringLiteralVisitor(); visitor.Visit(root); foreach (var literal in visitor.Literals) Console.WriteLine(literal);
程式輸出如下:
當然還可以使用root.DescendantNodes方法來簡化上面的過程。我在例子中使用Visitor的目的就是為了體現Roslyn的語法解析功能。
對VB.NET語言的應用
上面的輸入程式碼是一段C#的程式,如果是VB.NET的原始碼,其實處理過程是一樣的,無非就是將引用的名稱空間從Roslyn.Compilers.CSharp改為Roslyn.Compilers.VisualBasic。注意:Roslyn.Compilers.CSharp和Roslyn.Compilers.VisualBasic下都有SyntaxTree等型別的定義,但這些型別都是獨立的,並非從某個基類繼承或實現了某些介面,在實際應用中還得注意這點。
應用場景的思考
Roslyn的應用場景應該還是很多的,比如大家熟悉的FxCop,能夠根據一些規則來檢測託管程式集是否滿足這些規則,以保證質量。但FxCop很侷限,它需要使用反射,並根據程式集的除錯資訊PDB檔案進行規則判斷,而對於原始碼本身的規範校驗就不太適用了。仔細思考,Roslyn卻能夠在保證原始碼編寫規範方面,起到一定的作用。比如:
- 對定義的變數名、函式名等進行拼寫檢查
- 檢查註釋語句中的拼寫錯誤
- 檢查變數、函式等的命名規範
- XML文件的自動化翻譯(可以藉助Bing Translate、Google Translate的API實現自動化翻譯),等等
大家也可以在實際中總結一些能夠使用Roslyn的場景,我想只要合理利用,一定能在實際工作中幫助我們提高效率,做到事半功倍。