使用Microsoft Roslyn提取C#和VB.NET源代碼中的字符串常量


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以上):

image

在打開的對話框中,搜索Roslyn,並將Roslyn安裝到項目中:

SNAGHTMLdbda5b

首先創建一個語法樹的訪問者,它繼承於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);

程序輸出如下:

image

當然還可以使用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的場景,我想只要合理利用,一定能在實際工作中幫助我們提高效率,做到事半功倍。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM