【问题标题】:Using Roslyn, how to enumerate members (Namespaces, classes etc) details in Visual Basic Document?使用 Roslyn,如何在 Visual Basic 文档中枚举成员(命名空间、类等)详细信息?
【发布时间】:2018-05-01 17:13:26
【问题描述】:

使用 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成员?

【问题讨论】:

    标签: roslyn roslyn-code-analysis


    【解决方案1】:

    不仅存在一种获取方式:

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

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

    2) 更有用的方法 - 使用SemanticModel 获取您想要的数据: 这样,您将只需要接收ClassStatementSyntaxModuleStatementSyntxtNamespaceStatementSyntax 的语义信息,并且只需调用GetMembers() 即可接收到它们的所有成员:

    ...
    
      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

    【讨论】:

    • 知道为什么 startLine 和 endLine 的值相同吗?
    • @JoginderSNahil,这意味着你有一个可能完全位于一行的声明,例如FieldDeclarationSyntax,PropertyDeclarationSyntax(没有GetSet),@ 987654338@(对于MustOverride方法)可以定位在一行等等,所以startLine和endLine是一样的,但是startPosition和endPosition当然是不同的。
    • 我只分析了命名空间和类声明,它们不在同一行。这个逻辑对你有用吗?
    • @JoginderSNahil,我很抱歉,我真的相信ISymbol.Locations 包含项目的完整跨度,而不仅仅是声明的开始。我更新了LocationsDeclaringSyntaxReferencesDeclaringSyntaxReferences的用法
    • 您的更改完美运行。非常感谢您提供如此详细的答案。
    猜你喜欢
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 2011-09-12
    • 2019-10-23
    相关资源
    最近更新 更多