[英]How do I remove regions from code programatically using Roslyn?
我正在使用Roslyn從文本中解析C#代碼。 一些代碼具有圍繞多個類的區域。 例:
#region Classes
public class MyClass
{
}
public class MyClass2
{
#region Methods
#endregion
}
#endregion
我想刪除類周圍的區域(上例中的“類”),但保留內部區域,就像上面示例中名為“Methods”的區域一樣。 我該怎么做呢?
區域相當特殊,因為它們不遵循通常的樹形結構。 例如,您可以創建一個這樣的構造:
public class TestClass{
public void TestMethod(){
#region TestRegion
}
}
#endregion
這仍然有效。 考慮到這一點,在分析區域時還有一個問題:它們是瑣事中的節點。 因此,要獲取相關節點,您可以使用SyntaxRewriter(並傳遞構造函數“true”以啟用瑣事分析)或使用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);
}
}
正如Sievajet建議的那樣,您可以使用CSharpSyntaxRewriter
刪除附加到特定節點的Region
(在您的情況下: ClassDeclarationSyntax
)。
這是讓你入門的代碼:
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
PS:這不是完整的解決方案。 我同意mjwills ,你應該在發布問題之前先顯示一些進展。
PS:代碼的靈感來自於JoshVarty的EmptyStatementRemoval
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.