Roslyn 对 SyntaxTree 构造表示怀疑
本文关键字:表示 怀疑 SyntaxTree Roslyn | 更新日期: 2023-09-27 18:19:10
免责声明
我很确定我错过了一些明显的东西,但即使在阅读了官方文档之后,我也不清楚 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子语法节点的集合?
我错过了什么?
在聊天讨论之后,我们确定问题是要解析的代码是用以下方法构建的:
string[]lines = System.IO.File.ReadAllLines(filename);
string tocompile = string.Join(string.Empty, lines);
这会将所有代码放在一行上。 因此,//
之后的所有内容都成为评论。 解决方案只是使用 Environment.NewLine
作为连接字符,或使用 ReadAllText
而不是 ReadAllLines
。
由于注释可以出现在源代码中的任何位置,因此它们不会被建模为ChildNode
,这是为真正的语法元素保留的。相反,它们被认为是 SyntaxTrivia
. 在您的示例中,您应该能够查看方法的LeadingTrivia
并查看注释。
此外,由于这是一个XML文档注释,它可能有自己的有趣结构,因此将被建模为它自己的小树,您可以使用SyntaxTrivia
的GetStructure()
方法获得。
对于这种情况,使用 CSharpSyntaxWalker
可能会有很大帮助。
以下是从Josh Varty的博客中提取的示例,它有助于在控制台上打印语法树:
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());
}
还可以通过在语法节点上调用 GetLeadingTrivia
和 GetTrailingTrivia
方法来打印琐事。