如何使用Roslyn以编程方式从代码中删除区域?

我使用Roslyn从文本解析C#代码。一些代码具有围绕多个类的区域。例如:如何使用Roslyn以编程方式从代码中删除区域?

#region Classes 

public class MyClass

{

}

public class MyClass2

{

#region Methods

#endregion

}

#endregion

我想移除周围的类(“类”在上面的例子)的区域,但离开内部区域完好像一个命名在上面的例子中“方法”。我怎么能这样做呢?

回答:

由于Sievajet建议,您可以使用CSharpSyntaxRewriter删除连接到特定节点(在您的情况下:ClassDeclarationSyntaxRegion

这里是代码,让你开始:

public class RegionRemoval : CSharpSyntaxRewriter 

{

public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)

{

if(node.HasLeadingTrivia)

{

var enumerator = node.GetLeadingTrivia().GetEnumerator();

while(enumerator.MoveNext())

{

var syntaxTrivia = enumerator.Current;

if(syntaxTrivia.Kind().Equals(SyntaxKind.RegionDirectiveTrivia))

{

node = node.ReplaceTrivia(syntaxTrivia, SyntaxFactory.Whitespace("\n"));

}

}

}

return node;

}

}

class RoslynTry

{

public static void RegionRemover()

{

//A syntax tree with an unnecessary semicolon on its own line

var tree = CSharpSyntaxTree.ParseText(@"

#region Classes

public class MyClass

{

}

public class MyClass2

{

#region Methods

#endregion

}

#endregion

");

var rewriter = new RegionRemoval();

var result = rewriter.Visit(tree.GetRoot());

Console.WriteLine(result.ToFullString());

}

}

你的输出应该是这样的:

 public class MyClass 

{

}

public class MyClass2

{

#region Methods

#endregion

}

#endregion

附: :这不是完整的解决方案。我同意mjwills,你应该在发布问题之前展示一些进展。

P.S. :代码的灵感来源于JoshVarty的EmptyStatementRemoval

回答:

区域比较特殊,因为它们不遵循通常的树状结构。例如,您可以创建如下构造:

public class TestClass{ 

public void TestMethod(){

#region TestRegion

}

}

#endregion

这仍然有效。考虑到这一点,分析区域时还有一个额外的问题:它们是琐事中的节点。因此,要获取相关节点,您可以使用SyntaxRewriter(并传递构造函数“true”以启用trivia分析),或使用node.DescendantNodes(descendIntoTrivia:true)查找后代节点。

由于区域的开始和结束可能位于文件中的任何位置,因此应始终从语法树的根部开始分析以确保能够找到区域的结尾/开始。

为了找到该区域,您可以重写VisitRegionDirectiveTrivia以及VisitEndRegionDirectiveTrivia。由于RegionTrivia的开始和结束彼此不了解,所以您需要自己匹配。在下面的例子中,我简单地计算了我已经通过了多少个区域,并且记录了当走出一个区域时应该删除的#endregion位置的列表。

为了确定相关区域,我提供了两种方法:您可以使用区域的名称,也可以确定附加的节点是否是ClassDeclaration。

这两种方法都没有考虑类声明之前的属性声明等情况。如果你想处理这个问题,你需要看看兄弟节点,并检查它们中的任何一个是否在该区域的范围内开始。

private class RegionSyntaxRewriter : CSharpSyntaxRewriter 

{

int currentPosition = 0;

private List<int> EndRegionsForDeletion = new List<int>();

private string deletedRegion;

private bool useRegionNameForAnalysis = false;

public RegionSyntaxRewriter(string deletedRegion) : base(true)

{

this.deletedRegion = deletedRegion;

}

public override SyntaxNode VisitRegionDirectiveTrivia(

RegionDirectiveTriviaSyntax node)

{

currentPosition++;

var regionText = node.ToFullString().Substring(8).Trim();

if (!useRegionNameForAnalysis &&

node.ParentTrivia.Token.Parent is ClassDeclarationSyntax)

{

EndRegionsForDeletion.Add(currentPosition);

return SyntaxFactory.SkippedTokensTrivia();

}

if (useRegionNameForAnalysis &&

regionText == deletedRegion)

{

EndRegionsForDeletion.Add(currentPosition);

return SyntaxFactory.SkippedTokensTrivia();

}

return base.VisitRegionDirectiveTrivia(node);

}

public override SyntaxNode VisitEndRegionDirectiveTrivia(

EndRegionDirectiveTriviaSyntax node)

{

var oldPosition = currentPosition;

currentPosition--;

if (EndRegionsForDeletion.Contains(oldPosition))

{

EndRegionsForDeletion.Remove(currentPosition);

return SyntaxFactory.SkippedTokensTrivia();

}

return base.VisitEndRegionDirectiveTrivia(node);

}

}

以上是 如何使用Roslyn以编程方式从代码中删除区域? 的全部内容, 来源链接: utcz.com/qa/262844.html

回到顶部