使用 Roslyn,如何枚举 Visual Basic 文档中的成员(命名空间、类 等)详细信息?

Using Roslyn, how to enumerate members (Namespaces, classes etc) details in Visual Basic Document?

使用 Roslyn,确定 Visual Basic 文档成员的唯一机制似乎是:

var members = SyntaxTree.GetRoot().DescendantNodes().Where(node =>
      node is ClassStatementSyntax ||
      node is FunctionAggregationSyntax ||
      node is IncompleteMemberSyntax ||
      node is MethodBaseSyntax ||
      node is ModuleStatementSyntax ||
      node is NamespaceStatementSyntax ||
      node is PropertyStatementSyntax ||
      node is SubNewStatementSyntax
    );

如何获取每个成员的成员nameStarLineNumberEndLineNumber

不仅存在获得它的一种方法:

1)当你尝试时:我不会为所有善良的成员展示这种方式(他们数量庞大,逻辑相似),但只有其中一个,例如ClassStatementSyntax :

  • 要获得它的名字,只需 ClassStatementSyntax.Identifier.ValueText
  • 要获取起始行,您可以使用 Location 作为其中一种方法:
var location = Location.Create(SyntaxTree, ClassStatementSyntax.Identifier.Span);
var startLine = location.GetLineSpan().StartLinePosition.Line;
  • 检索结束行的逻辑看起来像接收开始行的逻辑,但它依赖于相应的结束语句(某种结束语句或自身)

2) 更有用的方法——使用SemanticModel来获取你想要的数据: 通过这种方式,您将只需要接收 ClassStatementSyntaxModuleStatementSyntxtNamespaceStatementSyntax 的语义信息,并且只需调用 GetMembers():[=23= 即可接收到它们的所有成员]

...

  SemanticModel semanticModel = // usually it is received from the corresponding compilation
  var typeSyntax = // ClassStatementSyntax, ModuleStatementSyntxt or NamespaceStatementSyntax
  string name = null;
  int startLine;
  int endLine;

  var info = semanticModel.GetSymbolInfo(typeSyntax);
  if (info.Symbol is INamespaceOrTypeSymbol typeSymbol)
  {
      name = typeSymbol.Name; // retrieve Name
      startLine = semanticModel.SyntaxTree.GetLineSpan(typeSymbol.DeclaringSyntaxReferences[0].Span).StartLinePosition.Line; //retrieve start line
      endLine = semanticModel.SyntaxTree.GetLineSpan(typeSymbol.DeclaringSyntaxReferences[0].Span).EndLinePosition.Line; //retrieve end line
      foreach (var item in typeSymbol.GetMembers())
      {
          // do the same logic for retrieving name and lines for all others members without calling GetMembers()
      }
  }
  else if (semanticModel.GetDeclaredSymbol(typeSyntax) is INamespaceOrTypeSymbol typeSymbol2)
  {
      name = typeSymbol2.Name; // retrieve Name
      startLine = semanticModel.SyntaxTree.GetLineSpan(typeSymbol2.DeclaringSyntaxReferences[0].Span).StartLinePosition.Line; //retrieve start line
      endLine = semanticModel.SyntaxTree.GetLineSpan(typeSymbol2.DeclaringSyntaxReferences[0].Span).EndLinePosition.Line; //retrieve end line

      foreach (var item in typeSymbol2.GetMembers())
      {
          // do the same logic for retrieving name and lines for all others members without calling GetMembers()
      }
  }

但是请注意,当您有部分声明时,您的 DeclaringSyntaxReferences 将有几个项目,因此您需要根据当前的 SyntaxTree

过滤 SyntaxReference