You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Roslyn提取C#代码中分组单行注释的技术问询

合并连续单行注释的Roslyn实现方案

我之前也遇到过类似的需求,用Roslyn处理注释的时候,连续的单行//注释被拆成了多个单独的SingleLineCommentTrivia,确实有点麻烦。这里分享一个我验证过的实现思路,核心是通过注释的位置关系来分组合并:

核心思路

Roslyn会将每一行//注释标记为独立的语法 trivia,但连续的单行注释在文本上是相邻的(中间只有换行、空格这类空白字符)。我们可以通过以下步骤来分组:

  • 遍历语法树,收集所有的SingleLineCommentTrivia;
  • 按注释在文本中的出现顺序,检查相邻两个注释之间的文本是否仅包含空白字符;
  • 如果是,则将它们归为同一组,否则开启新的分组;
  • 最后将每组的单行注释内容合并成一个完整的块。

具体代码实现

下面是一个完整的代码片段,假设你已经有了SyntaxTree实例:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public static class CommentExtractor
{
    public static List<string> GetCombinedSingleLineComments(SyntaxTree tree)
    {
        var root = tree.GetRoot();
        // 收集所有单行注释trivia,并按文本出现顺序排序
        var singleLineComments = root.DescendantTrivia()
            .Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia))
            .OrderBy(t => t.Span.Start)
            .ToList();

        var combinedComments = new List<string>();
        if (!singleLineComments.Any())
            return combinedComments;

        // 初始化第一个分组的内容构建器
        var currentGroupBuilder = new StringBuilder();
        currentGroupBuilder.AppendLine(singleLineComments[0].ToString().TrimStart('/').Trim());

        for (int i = 1; i < singleLineComments.Count; i++)
        {
            var prevComment = singleLineComments[i - 1];
            var currentComment = singleLineComments[i];

            // 获取两个注释之间的文本范围
            var betweenSpan = TextSpan.FromBounds(prevComment.Span.End, currentComment.Span.Start);
            var betweenText = tree.GetText().GetSubText(betweenSpan).ToString();

            // 判断中间是否只有空白字符(换行、空格、制表符等)
            if (string.IsNullOrWhiteSpace(betweenText))
            {
                // 加入当前分组,去掉开头的//并修剪前后空格
                currentGroupBuilder.AppendLine(currentComment.ToString().TrimStart('/').Trim());
            }
            else
            {
                // 保存当前分组,开始新分组
                combinedComments.Add(currentGroupBuilder.ToString().TrimEnd());
                currentGroupBuilder.Clear();
                currentGroupBuilder.AppendLine(currentComment.ToString().TrimStart('/').Trim());
            }
        }

        // 加入最后一个未保存的分组
        combinedComments.Add(currentGroupBuilder.ToString().TrimEnd());
        return combinedComments;
    }
}

额外说明

  • 这个方法会自动忽略注释之间的空白(包括多个换行、空格、制表符),只要它们没有被非空白内容隔开,就会被合并成一个块;
  • 如果需要区分不同代码块中的连续注释(比如类上面的连续注释和方法内部的),可以在收集trivia的时候,额外记录它们所属的SyntaxNode,然后按节点分组后再处理;
  • 如果你想保留注释的原始格式(比如//后面的缩进),可以去掉代码中的Trim(),只保留TrimStart('/')来移除开头的注释符号。

这样处理后,你就能把连续的单行注释作为一个整体提取出来,和多行注释、文档注释的处理逻辑对齐了。

内容的提问来源于stack exchange,提问作者Makilll

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:01:12