将 2 种方法(包括评论琐事)与罗斯林进行比较

本文关键字:罗斯林 比较 方法 评论 包括 | 更新日期: 2023-09-27 18:32:53

>我需要在 c# 代码中执行 2 个方法之间的比较,我找到了SyntaxNode.IsEquivalentTo,但如果方法是:

public void Method1()
{
    //hello
}

public void Method1()
{  
}

返回值为 : True

Rslyn API 还有其他方法可以执行比较,包括评论琐事吗?(在上面的例子中得到:假??

(我不使用常规字符串比较的原因是我不希望空格和新行不算作差异,例如:

public void Method1()
{
    int i=1;
}

public void Method1(){
    int i=1  ;
}

将是平等的。

将 2 种方法(包括评论琐事)与罗斯林进行比较

在撰写本文时,没有内置方法支持此类比较,但使用语法重写器编写一个方法很容易

基本思想非常简单。编写一个CSharpSyntaxRewriter,该将从两个比较的节点中删除所有非注释琐事,然后使用内置的IsEquivalentTo()方法比较新创建的节点。

下面的代码执行您正在寻找的操作。要比较两个节点(在您的情况下MethodDeclarationSyntax(,只需调用:

firstNode.IsEquivalentToWithCommentsPreserved(secondNode);

以下是实现:

public static class SyntaxNodeExtensions
{
    public static bool IsEquivalentToWithCommentsPreserved(this SyntaxNode syntaxNode, SyntaxNode otherNode)
    {
        var triviaRemover = new NonCommentTriviaRemover();
        return triviaRemover.Visit(syntaxNode)
               .IsEquivalentTo(triviaRemover.Visit(otherNode));
    }
    private class NonCommentTriviaRemover : CSharpSyntaxRewriter
    {
        private static readonly SyntaxTrivia EmptyTrivia = default(SyntaxTrivia);
        public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
        {
            return trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                   trivia.IsKind(SyntaxKind.MultiLineCommentTrivia)
                ? trivia // Preserve comments by returning the original comment trivia.
                : EmptyTrivia; // Remove all other trivias.
        }
    }
}

请记住,此代码不会忽略注释中琐事的最终差异。这意味着,这两个版本的方法将被视为不等效:

void Method()
{
    // Some comment.
}
void Method()
{
    // Some      comment.
}

如果您还需要忽略这些差异,请告诉我。然后,我可以扩展解决方案以涵盖这种情况。

我快速在以下重要示例中尝试了该解决方案,并且效果很好:

var firstCode =
@"
    // First comment.
    // Second comment.
    int x(int a)
    {
        // This is a comment.
        // And this as well.
        if (a == 1) // This also
        {
            return 0 ;
        }
        /*
            Multi line comment.
        */if(a == -5) return -10   ;
        if (a == 2)
                return 0 ;
        return 5;
    }
";
var secondCode =
@"
    // First comment.
    // Second comment.
    int x(int a)
    {
        // This is a comment.
        // And this as well.
                if    (a 
                == 1) // This also
        {
            return     0 ;
              }
        /*
            Multi line comment.
        */
        if(a == -5) return -10   ;
        if (a == 2) return 0 ;
        return 5;

    }
";
var firstMethod = CSharpSyntaxTree.ParseText(firstCode).GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var secondMethod = CSharpSyntaxTree.ParseText(secondCode).GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
Console.WriteLine($"{firstMethod.IsEquivalentTo(secondMethod)}"); // Prints false.
Console.WriteLine($"{firstMethod.IsEquivalentToWithCommentsPreserved(secondMethod)}"); // Prints true.

不过,在生产中使用代码之前,最好为其编写适当的单元测试,null检查等;-(

如果它们需要完全相同,您可以简单地在节点上调用node.ToString()并比较字符串。