C# Roslyn对合成树结构的质疑 免责声明
我很确定我遗漏了一些明显的东西,但即使在阅读了官方文档之后,我也不清楚Roslyn是如何创建语法树的 例子 考虑以下简单代码:C# Roslyn对合成树结构的质疑 免责声明,c#,.net,roslyn,C#,.net,Roslyn,我很确定我遗漏了一些明显的东西,但即使在阅读了官方文档之后,我也不清楚Roslyn是如何创建语法树的 例子 考虑以下简单代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace aopsample { class UsbReadWriter { public bool ReadFromUsb()
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
,并制作了类似的东西,非常粗糙和简单,但我只需要理解
它工作得很好
麻烦
但是,向ReadFromUsb()
方法添加注释就足够了,类似这样
/// <summary>
/// Reads a data from Usb
/// </summary>
/// <returns></returns>
public bool ReadFromUsb()
{
return true;
}
//
///从Usb读取数据
///
///
公共bool ReadFromUsb()
{
返回true;
}
而ChildNodes()
调用{1}标记行,对于类(?)返回0
问题:
为什么向成员函数添加注释会重置父类子语法节点的集合
我遗漏了什么?由于注释可以出现在源代码中的任何地方,因此它们没有建模为
子节点,而子节点是为真正的语法元素保留的。相反,它们被视为SyntaxTrivia
。在您的示例中,您应该能够查看该方法的LeadingTrivia
,并查看注释
此外,由于这是一个XML文档注释,它可能有自己有趣的结构,因此它将被建模为自己的小树,您可以在聊天讨论之后使用SyntaxTrivia
的GetStructure()
方法获得它,我们确定问题在于要解析的代码的构造方法:
string[]lines = System.IO.File.ReadAllLines(filename);
string tocompile = string.Join(string.Empty, lines);
将所有代码放在一行上。因此,/
之后的所有内容都成为注释。解决方案就是使用环境。换行符
作为连接字符,或者使用ReadAllText
而不是ReadAllLines
对于这种情况,使用CSharpSyntaxWalker
会有很大帮助
以下是从博客中提取的示例,有助于在控制台上打印语法树:
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
和getRailingTrivia
方法来打印琐事。作为旁注,我认为使用LINQ会使zour代码更加清晰。我认为这通常适用于在Roslyn中选择节点。@svick:是的,好的。正如我所说的,这段代码只是“快速和肮脏”。好吧,但问题不是:我如何在孩子们之间找到注释,而是为什么添加新注释会(显然)影响语法树结构。事实上,考虑到注释
例如空格
,预处理器dirrectives
不构成语法树结构的一部分,为什么添加/删除它们会以任何方式影响父SyntaxNode的子级?对文件的每次编辑都会使其进入不同的树。在RoslynSyntaxTree
和SyntaxNode
中,对象是不可变的,并且完全具有代表性。一旦构建,它们就永远不会更改,并且对文件中的每一位文本进行建模。这意味着,如果对代码进行更改,每次都会返回不同的树,因为ChildNodes
的Span
属性值不同。请注意,如果在Visual Studio中编辑,我们使用增量解析策略,这样我们实际上在解析之间共享树的大部分内部存储,它只是在访问时创建的一层薄薄的包装器对象,实际上每次都是新的。白皮书很好地解释了我们在这里使用的“重新旋转”过程,但我每次都会自然地重新构建它。当我更改一个源文件时,我会停止并重建我的程序,因此,据我所知,我从一个“新”文件重建了一个语法树?你是以编程方式做的吗?如果是这样,并且您正在使用类似于SyntaxNode.Replace
,则需要保留返回值并查看其树以查看更改的节点。
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());
}