Roslyn怀疑SyntaxTree的构造

时间:2011-12-30 17:40:03

标签: c# .net roslyn

声明

我很确定我遗漏了一些明显的东西,但即使在阅读官方文档后,我也不清楚Roslyn如何创建语法树。

实施例

考虑以下简单代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace aopsample
{

    class UsbReadWriter
    {

        public bool ReadFromUsb()
        {
            return true;
        }

        public virtual bool WriteToUsb()
        {
            return true;
        }
    }
}

我为这段代码得到SyntaxTree并做了类似的事情,非常粗糙和简单,但我只需要理解。

  string[]lines =  System.IO.File.ReadAllLines(filename);      
  string tocompile = string.Join(string.Empty, lines);  

  SyntaxNode root = tree.GetRoot(new CancellationToken());
  foreach (SyntaxNode sn in root.ChildNodes())
  {
      if (sn.Kind == SyntaxKind.NamespaceDeclaration)
      {
         //I get a namespace, so it's Child node just will be class
         foreach (SyntaxNode sname in sn.ChildNodes())
         {
             if (sname.Kind == SyntaxKind.ClassDeclaration)
             {
                 //I get class, so it's  Children will be methods of the class        
                 foreach (SyntaxNode sclass in sname.ChildNodes()) // **{1}** 
                 {
                     if (sclass.Kind == SyntaxKind.MethodDeclaration) 
                     {

                     }
                 }
             }
        }

它运作良好。

故障

但是,它足以为ReadFromUsb()方法添加注释,就像这样

/// <summary>
/// Reads a data from Usb
/// </summary>
/// <returns></returns>
public bool ReadFromUsb()
{
    return true;
}

ChildNodes()调用{1}标记的行, CLASS (???)返回0.

问题

为什么要向成员函数添加注释,重置父CLASS子句的集合语法节点?

我错过了什么?

3 个答案:

答案 0 :(得分:10)

在聊天讨论之后,我们确定问题是要解析的代码正在构建:

string[]lines = System.IO.File.ReadAllLines(filename); 
string tocompile = string.Join(string.Empty, lines);

将所有代码放在一行上。因此//之后的所有内容都会成为评论。解决方案只是使用Environment.NewLine作为连接字符,或使用ReadAllText代替ReadAllLines

答案 1 :(得分:3)

由于注释可以出现在源代码中的任何位置,因此它们不会被建模为ChildNode,它们是为真正的语法元素保留的。相反,它们被视为SyntaxTrivia。在您的示例中,您应该能够查看方法的LeadingTrivia并查看注释。

此外,由于这是一个XML文档注释,它可能具有自己的有趣结构,因此它将被建模为它自己的小树,您可以使用GetStructure()的{​​{1}}方法获得该树。

答案 2 :(得分:1)

对于这种情况,使用CSharpSyntaxWalker可能会有很大帮助。

以下是从Josh Varty's博客here中提取的示例,该示例有助于在控制台上打印语法树:

 public class CustomWalker : CSharpSyntaxWalker
{
    static int Tabs = 0;
    public override void Visit(SyntaxNode node)
    {
        Tabs++;
        var indents = new String('\t', Tabs);
        Console.WriteLine(indents + node.Kind());
        base.Visit(node);
        Tabs--;
    }
}

static void Main(string[] args)
{
    var tree = CSharpSyntaxTree.ParseText(@"
        public class MyClass
        {
            public void MyMethod()
            {
            }
            public void MyMethod(int n)
            {
            }
       ");

    var walker = new CustomWalker();
    walker.Visit(tree.GetRoot());
}

您还可以通过在语法节点上调用GetLeadingTriviaGetTrailingTrivia方法来打印trivias。