C# 与Roslyn比较2种方法,包括评论和琐事
我需要在c代码中对两种方法进行比较, 我发现SyntaxNode.IsEquivalentTo,但如果方法是:C# 与Roslyn比较2种方法,包括评论和琐事,c#,roslyn,C#,Roslyn,我需要在c代码中对两种方法进行比较, 我发现SyntaxNode.IsEquivalentTo,但如果方法是: public void Method1() { //hello } 及 返回值为:True Rslyn API是否有其他方法来执行比较,包括注释和琐事?? (在上面的例子中得到:False??) (我不使用常规字符串比较的原因是我不希望空格和新行不算作差,例如: public void Method1() { int i=1; } 及 将相等。如果它们需要完全相同,
public void Method1()
{
//hello
}
及
返回值为:True
Rslyn API是否有其他方法来执行比较,包括注释和琐事??
(在上面的例子中得到:False??)
(我不使用常规字符串比较的原因是我不希望空格和新行不算作差,例如:
public void Method1()
{
int i=1;
}
及
将相等。如果它们需要完全相同,您只需在节点上调用
node.ToString()
,然后比较字符串。在编写本文时,没有内置方法支持这种比较,但使用语法重写器编写一个方法很容易
基本思想非常简单。编写一个函数,从两个比较的节点中删除所有非注释性琐事,然后使用内置方法比较新创建的节点
下面的代码就是您要查找的。要比较两个节点(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.
var firstCode=
@"
//第一条评论。
//第二条评论。
整数x(整数a)
{
//这是一个评论。
//还有这个。
如果(a==1)//这也是
{
返回0;
}
/*
多行注释。
*/如果(a==-5)返回-10;
如果(a==2)
返回0;
返回5;
}
";
var第二代码=
@"
//第一条评论。
//第二条评论。
整数x(整数a)
{
//这是一个评论。
//还有这个。
如果(a)
==1)//这也是
{
返回0;
}
/*
多行注释。
*/
如果(a==-5)返回-10;
如果(a==2)返回0;
返回5;
}
";
var firstMethod=CSharpSyntaxTree.ParseText(firstCode).GetRoot().genderantNodes().OfType().First();
var secondMethod=CSharpSyntaxTree.ParseText(secondCode.GetRoot().genderantnodes().OfType().First();
Console.WriteLine($“{firstMethod.IsEquivalentTo(secondMethod)}”);//打印为false。
Console.WriteLine($“{firstMethod.IsequivalentToWithCommentsReserved(secondMethod)}”);//打印true。
尽管如此,在产品中使用代码之前,最好为其编写适当的单元测试、空检查等;-)但我不希望额外的空间或新行被视为差异,而使用ToString()则会……空格、新行和注释都是琐事。所以我认为你想比较平等,包括琐事,但没有空格琐事?是的,所有的代码和注释都将包括在内。不包括空格和额外的新行
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.