将 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 ;
}
将是平等的。
在撰写本文时,没有内置方法支持此类比较,但使用语法重写器编写一个方法很容易。
基本思想非常简单。编写一个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()
并比较字符串。