我已经想出了如何打开解决方案然后遍历项目然后迭代文档.我一直在寻找如何查找C#类,枚举,结构和接口,这些可能在声明结尾处有一个无关的分号(C++风格).我想删除它们并将.cs文件保存回磁盘.在我现在的公司写了大约25个解决方案,我会反对.注意:我们这样做的原因是为了推进更好的编码标准.(我想学习如何使用Roslyn进行这些'简单'调整)
示例(更新):
class Program { static void Main(string[] args) { string solutionFile = @"S:\source\dotnet\SimpleApp\SimpleApp.sln"; IWorkspace workspace = Workspace.LoadSolution(solutionFile); var proj = workspace.CurrentSolution.Projects.First(); var doc = proj.Documents.First(); var root = (CompilationUnitSyntax)doc.GetSyntaxRoot(); var classes = root.DescendantNodes().OfType(); foreach (var decl in classes) { ProcessClass(decl); } Console.ReadKey(); } private static SyntaxNode ProcessClass(ClassDeclarationSyntax node) { ClassDeclarationSyntax newNode; if (node.HasTrailingTrivia) { foreach (var t in node.GetTrailingTrivia()) { var es = new SyntaxTrivia(); es.Kind = SyntaxKind.EmptyStatement; // kind is readonly - what is the right way to create // the right SyntaxTrivia? if (t.Kind == SyntaxKind.EndOfLineTrivia) { node.ReplaceTrivia(t, es); } } return // unsure how to do transform and return it } }
我要转换的示例代码
using System; public class Person { public string FirstName { get; set; } public string LastName { get; set; } }; // note: the semicolon at the end of the Person class
小智.. 10
这是一个小程序,它在解决方案中的所有类,结构,接口和枚举声明之后删除可选分号.程序循环遍历解决方案中的文档,并使用a SyntaxWriter
来重写syntaxtree.如果进行了任何更改,则使用新语法覆盖原始代码文件.
using System; using System.IO; using System.Linq; using Roslyn.Compilers.CSharp; using Roslyn.Services; namespace TrailingSemicolon { class Program { static void Main(string[] args) { string solutionfile = @"c:\temp\mysolution.sln"; var workspace = Workspace.LoadSolution(solutionfile); var solution = workspace.CurrentSolution; var rewriter = new TrailingSemicolonRewriter(); foreach (var project in solution.Projects) { foreach (var document in project.Documents) { SyntaxTree tree = (SyntaxTree)document.GetSyntaxTree(); var newSource = rewriter.Visit(tree.GetRoot()); if (newSource != tree.GetRoot()) { File.WriteAllText(tree.FilePath, newSource.GetText().ToString()); } } } } class TrailingSemicolonRewriter : SyntaxRewriter { public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } private SyntaxNode RemoveSemicolon(SyntaxNode node, SyntaxToken semicolonToken, FuncwithSemicolonToken) { if (semicolonToken.Kind != SyntaxKind.None) { var leadingTrivia = semicolonToken.LeadingTrivia; var trailingTrivia = semicolonToken.TrailingTrivia; SyntaxToken newToken = Syntax.Token( leadingTrivia, SyntaxKind.None, trailingTrivia); bool addNewline = semicolonToken.HasTrailingTrivia && trailingTrivia.Count() == 1 && trailingTrivia.First().Kind == SyntaxKind.EndOfLineTrivia; var newNode = withSemicolonToken(newToken); if (addNewline) return newNode.WithTrailingTrivia(Syntax.Whitespace(Environment.NewLine)); else return newNode; } return node; } } } }
希望它与您所寻找的一致.
这是一个小程序,它在解决方案中的所有类,结构,接口和枚举声明之后删除可选分号.程序循环遍历解决方案中的文档,并使用a SyntaxWriter
来重写syntaxtree.如果进行了任何更改,则使用新语法覆盖原始代码文件.
using System; using System.IO; using System.Linq; using Roslyn.Compilers.CSharp; using Roslyn.Services; namespace TrailingSemicolon { class Program { static void Main(string[] args) { string solutionfile = @"c:\temp\mysolution.sln"; var workspace = Workspace.LoadSolution(solutionfile); var solution = workspace.CurrentSolution; var rewriter = new TrailingSemicolonRewriter(); foreach (var project in solution.Projects) { foreach (var document in project.Documents) { SyntaxTree tree = (SyntaxTree)document.GetSyntaxTree(); var newSource = rewriter.Visit(tree.GetRoot()); if (newSource != tree.GetRoot()) { File.WriteAllText(tree.FilePath, newSource.GetText().ToString()); } } } } class TrailingSemicolonRewriter : SyntaxRewriter { public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node) { return RemoveSemicolon(node, node.SemicolonToken, t => node.WithSemicolonToken(t)); } private SyntaxNode RemoveSemicolon(SyntaxNode node, SyntaxToken semicolonToken, Func<SyntaxToken, SyntaxNode> withSemicolonToken) { if (semicolonToken.Kind != SyntaxKind.None) { var leadingTrivia = semicolonToken.LeadingTrivia; var trailingTrivia = semicolonToken.TrailingTrivia; SyntaxToken newToken = Syntax.Token( leadingTrivia, SyntaxKind.None, trailingTrivia); bool addNewline = semicolonToken.HasTrailingTrivia && trailingTrivia.Count() == 1 && trailingTrivia.First().Kind == SyntaxKind.EndOfLineTrivia; var newNode = withSemicolonToken(newToken); if (addNewline) return newNode.WithTrailingTrivia(Syntax.Whitespace(Environment.NewLine)); else return newNode; } return node; } } } }
希望它与您所寻找的一致.
此信息必须存储在ClassDeclaration节点中 - 因为根据C#规范,分号是其产生结束时的可选标记:
class-declaration:attributes opt class-modifiers opt partial opt class identifier type-parameter-list opt class-base opt type-parameter-constraints-clauses opt class-body ; 选择
UPDATE
根据Roslyn的文档,您实际上无法更改语法树 - 因为它们是不可变结构.这可能kind
是readonly 的原因.但是,您可以使用With*
为每个可更改树属性定义的方法创建一个新树,并使用ReplaceNode
.Roslyn文档有一个很好的例子:
var root = (CompilationUnitSyntax)tree.GetRoot(); var oldUsing = root.Usings[1]; var newUsing = oldUsing.WithName(name); //changes the name property of a Using statement root = root.ReplaceNode(oldUsing, newUsing);
为了将您的新树再次转换为代码(也就是漂亮的打印),您可以使用GetText()
编译单元节点中的方法(在我们的示例中,root
变量).
您还可以扩展SyntaxRewriter类以执行代码转换.罗斯林官方网站上有一个广泛的例子; 看一下这个特别的演练.以下命令将转换后的树写回原始文件:
SyntaxNode newSource = rewriter.Visit(sourceTree.GetRoot()); if (newSource != sourceTree.GetRoot()) { File.WriteAllText(sourceTree.FilePath, newSource.GetFullText()); }
其中rewriter是一个实例SyntaxRewriter
.