zoukankan      html  css  js  c++  java
  • 使用Microsoft Roslyn提取C#和VB.NET源代码中的字符串常量

    使用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代码中的字符串常量。

    字符串常量的提取

    先看下面的一段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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#的语法树,它的实现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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属性获得所有的字符串常量。

    1
    2
    3
    4
    5
    6
    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的场景,我想只要合理利用,一定能在实际工作中帮助我们提高效率,做到事半功倍。

  • 相关阅读:
    【BZOJ】1726 [Usaco2006 Nov]Roadblocks第二短路
    【BZOJ】1666 [Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏
    【BZOJ】1699 [Usaco2007 Jan]Balanced Lineup排队
    【BZOJ】1477 青蛙的约会
    【BZOJ】1385 [Baltic2000]Division expression
    【算法】数学
    【NOIP】提高组2012 同余方程
    【BZOJ】1096 [ZJOI2007]仓库建设
    【算法】动态规划
    【LA】5135 Mining Your Own Business
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3380277.html
Copyright © 2011-2022 走看看