我已经找到了如何打开解决方案然后遍历项目然后迭代文档。我一直在寻找如何查找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<ClassDeclarationSyntax>();
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
答案 0 :(得分:10)
这是一个小程序,它在解决方案中的所有类,结构,接口和枚举声明之后删除可选分号。程序循环遍历解决方案中的文档,并使用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;
}
}
}
}
希望它与你所寻找的东西一致。
答案 1 :(得分:8)
此信息必须存储在ClassDeclaration节点中 - 因为根据C#规范,分号是其产生结尾的可选标记:
类声明: attributes opt class-modifiers opt partial opt class identifier type-parameter-list opt class-base opt type-parameter-constraints-clauses opt class-body ; opt
<强>更新强>
根据Roslyn的文档,您实际上无法更改语法树 - 因为它们是不可变结构。这可能是kind
只读的原因。但是,您可以使用为每个可更改树属性定义的With*
方法创建一个新树,并使用ReplaceNode
。罗斯林文档有一个很好的例子:
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类以执行代码转换。罗斯林官方网站上有一个广泛的例子;看看this particular walkthrough。以下命令将转换后的树写回原始文件:
SyntaxNode newSource = rewriter.Visit(sourceTree.GetRoot());
if (newSource != sourceTree.GetRoot())
{
File.WriteAllText(sourceTree.FilePath, newSource.GetFullText());
}
其中rewriter是SyntaxRewriter
的实例。