如何使用Roslyn以编程方式从代码中删除区域?
我使用Roslyn从文本解析C#代码。一些代码具有围绕多个类的区域。例如:如何使用Roslyn以编程方式从代码中删除区域?
#region Classes public class MyClass
{
}
public class MyClass2
{
#region Methods
#endregion
}
#endregion
我想移除周围的类(“类”在上面的例子)的区域,但离开内部区域完好像一个命名在上面的例子中“方法”。我怎么能这样做呢?
回答:
由于Sievajet建议,您可以使用CSharpSyntaxRewriter
删除连接到特定节点(在您的情况下:ClassDeclarationSyntax
)Region
。
这里是代码,让你开始:
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