比较2方法,包括评论琐事与罗斯林

时间:2016-02-02 06:38:24

标签: c# roslyn

我需要在c#代码中对两个方法进行比较, 我找到了 SQLSTATE[42S22]: Column not found: 1054 Unknown column 'productRating' in 'where clause' (SQL: select `products`.*, AVG(rating) as 'productRating' from `products` left join `reviews` on `products`.`id` = `reviews`.`productID` where `products`.`status` = enable and (`categoryID` in (1, 3, 4, 8, 9, 11, 18, 21, 28, 31) and `productSellingPrice` between 50 and 5000 and `productRating` between 4 and 5) group by `products`.`id`) ,但是如果方法是:

SyntaxNode.IsEquivalentTo

public void Method1()
{
    //hello
}

返回值为:public void Method1() { }

有没有其他方法与Rslyn API进行比较,包括评论琐事? (在上面的例子中得到:False ??)

(我不使用常规字符串比较的原因是我不是那个空格而且新行不会算作差异,例如:

True

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

将是平等的。

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

在撰写本文时,没有内置方法来支持这种比较,但使用语法重写器很容易编写

基本思路很简单。编写一个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.
        }
    }
}

请记住,此代码不会忽略评论中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.

然而,在生产中使用代码之前,最好为它编写适当的单元测试,空检查等; - )