C# 使用Roslyn CodeAnalyzer向类添加命名空间
小猪后退 我正在创建一个C# 使用Roslyn CodeAnalyzer向类添加命名空间,c#,code-analysis,roslyn,roslyn-code-analysis,C#,Code Analysis,Roslyn,Roslyn Code Analysis,小猪后退 我正在创建一个CodeFixProvider,确保所有异步方法都使用CancellationToken: //Before Code Fix: public async Task Example(){} //After Code Fix public async Task Example(CancellationToken token){} 我可以将参数添加到方法中,但我必须使用Type.FullName来添加参数。相反,我想为System.Threading添加一个using语句
CodeFixProvider
,确保所有异步方法都使用CancellationToken
:
//Before Code Fix:
public async Task Example(){}
//After Code Fix
public async Task Example(CancellationToken token){}
我可以将参数添加到方法中,但我必须使用Type.FullName
来添加参数。相反,我想为System.Threading
添加一个using语句到类文件的顶部,这样该方法就不需要使用完整的名称空间。换言之:
// What I have thus far:
public class AClass{
public async Task Example(System.Threading.CancellationToken token){}
}
// What I want:
using System.Threading;
public class AClass{
public async Task Example(CancellationToken token){}
}
如何将using语句添加到文档
?
我尝试了几种方法,但在替换SyntaxTree
引用中的多个节点时,会丢失引用(因为树是不可变的,每次更改都会重新构建)
我可以部分使用下面的代码,但这仅在填充了compliationUnitSyntax.Using
属性时有效,而在命名空间之后使用语句时则不是这种情况。这还依赖于文件中已经存在至少一个使用语句的
有更好的方法吗
private async Task<Document> HaveMethodTakeACancellationTokenParameter(
Document document, SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
var syntaxTree =
(await document.GetSyntaxTreeAsync(cancellationToken))
.GetRoot(cancellationToken);
var method = syntaxNode as MethodDeclarationSyntax;
#region Add Parameter
var newParameter =
SyntaxFactory.Parameter(
SyntaxFactory.Identifier("cancellationToken")
)
.WithType(
SyntaxFactory.ParseTypeName(
typeof(CancellationToken).FullName));
var updatedMethod = method.AddParameterListParameters(newParameter);
syntaxTree = syntaxTree.ReplaceNode(method, updatedMethod);
#endregion
#region Add Using Statements
var compilation =
syntaxTree as CompilationUnitSyntax;
var systemThreadingUsingName =
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName("System"),
SyntaxFactory.IdentifierName("Threading"));
if (compilation.Usings.All(u => u.Name.GetText().ToString() != typeof(CancellationToken).Namespace))
{
syntaxTree = syntaxTree.InsertNodesAfter(compilation.Usings.Last(), new[]
{
SyntaxFactory.UsingDirective(
systemThreadingUsingName)
});
}
#endregion
return document.WithSyntaxRoot(syntaxTree);
}
专用异步任务HaveMethodTakeACancellationTokenParameter(
文档文档,SyntaxNode SyntaxNode,CancellationToken CancellationToken)
{
var-syntaxTree=
(等待文档。GetSyntaxTreeAsync(cancellationToken))
.GetRoot(取消令牌);
var method=syntaxNode作为MethodDeclarationSyntax;
#区域添加参数
新参数=
SyntaxFactory.Parameter(
SyntaxFactory.Identifier(“cancellationToken”)
)
.WithType(
SyntaxFactory.ParseTypeName(
typeof(CancellationToken.FullName));
var updateMethod=method.AddParameterListParameters(newParameter);
syntaxTree=syntaxTree.ReplaceNode(方法,updateMethod);
#端区
#使用语句添加区域
变量编译=
syntaxTree作为CompliationUnitSyntax;
var systemThreadingUsingName=
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName(“系统”),
SyntaxFactory.IdentifierName(“线程”);
if(compilation.Usings.All(u=>u.Name.GetText().ToString()!=typeof(CancellationToken.Namespace))
{
syntaxTree=syntaxTree.InsertNodesAfter(compilation.Usings.Last(),new[]
{
SyntaxFactory.UsingDirective(
systemThreadingUsingName)
});
}
#端区
返回文档。使用SyntaxRoot(syntaxTree);
}
一个选项是用注释标记所有方法、添加using语句、查找带注释的方法、更改所有方法以及删除注释
正如您所说,树是不可变的,但是注释在修改过程中不会丢失。因此,您需要以下内容:
var annotation = new SyntaxAnnotation();
var newRoot = root.ReplaceNode(
method,
method.WithAdditionalAnnotations(annotation));
newRoot = AddUsing(newRoot);
method = newRoot.GetAnnotatedNodes(annotation).First();
var newMethod = ChangeParameters(method);
newRoot = root.ReplaceNode(method, newMethod.WithoutAnnotations(annotation));
全面实施:
private async Task<Document> HaveMethodTakeACancellationTokenParameter(
Document document, SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
var method = syntaxNode as MethodDeclarationSyntax;
var cancellationTokenParameter =
SyntaxFactory.Parameter(
SyntaxFactory.Identifier("cancellationToken")
)
.WithType(
SyntaxFactory.ParseTypeName(
typeof(CancellationToken).Name));
var root =
(await document.GetSyntaxTreeAsync(cancellationToken))
.GetRoot(cancellationToken);
var annotation = new SyntaxAnnotation();
var newRoot = root.ReplaceNode(
method,
method.WithAdditionalAnnotations(annotation));
#region Add Using Statements
var systemThreadingUsingStatement =
SyntaxFactory.UsingDirective(
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName("System"),
SyntaxFactory.IdentifierName("Threading")));
var compilation =
newRoot as CompilationUnitSyntax;
if (null == compilation)
{
newRoot =
newRoot.InsertNodesBefore(
newRoot.ChildNodes().First(),
new[] {systemThreadingUsingStatement});
}
else if (compilation.Usings.All(u => u.Name.GetText().ToString() != typeof(CancellationToken).Namespace))
{
newRoot =
newRoot.InsertNodesAfter(compilation.Usings.Last(),
new[]{ systemThreadingUsingStatement });
}
#endregion
method = (MethodDeclarationSyntax)newRoot.GetAnnotatedNodes(annotation).First();
var updatedMethod = method.AddParameterListParameters(cancellationTokenParameter);
newRoot = newRoot.ReplaceNode(method, updatedMethod.WithoutAnnotations(annotation));
return document.WithSyntaxRoot(newRoot);
}
专用异步任务HaveMethodTakeACancellationTokenParameter(
文档文档,SyntaxNode SyntaxNode,CancellationToken CancellationToken)
{
var method=syntaxNode作为MethodDeclarationSyntax;
var cancellationTokenParameter=
SyntaxFactory.Parameter(
SyntaxFactory.Identifier(“cancellationToken”)
)
.WithType(
SyntaxFactory.ParseTypeName(
typeof(CancellationToken.Name));
变量根=
(等待文档。GetSyntaxTreeAsync(cancellationToken))
.GetRoot(取消令牌);
var annotation=新的SyntaxAnnotation();
var newRoot=root.ReplaceNode(
方法,,
方法。带有附加注释(注释));
#使用语句添加区域
var-systemThreadingUsingStatement=
SyntaxFactory.UsingDirective(
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName(“系统”),
SyntaxFactory.IdentifierName(“线程”);
变量编译=
newRoot作为CompilationUnitSyntax;
if(null==编译)
{
纽根=
newRoot.InsertNodesBefore(
newRoot.ChildNodes().First(),
新[]{systemThreadingUsingStatement});
}
else if(compilation.Usings.All(u=>u.Name.GetText().ToString()!=typeof(CancellationToken.Namespace))
{
新根=
newRoot.InsertNodesAfter(compilation.Usings.Last(),
新[]{systemThreadingUsingStatement});
}
#端区
method=(MethodDeclarationSyntax)newRoot.GetAnnotatedNodes(annotation.First();
var updateMethod=method.AddParameterListParameters(cancellationTokenParameter);
newRoot=newRoot.ReplaceNode(方法,updateMethod.WithoutAnnotations(注释));
返回文档。使用syntaxroot(newRoot);
}
使用文档编辑器
对单个文档进行多个更改。@Jeroenvanevel-是否有教程介绍如何在任何地方使用文档编辑器
?为什么不先修改该方法,然后添加using?很好。在这种情况下,这也有效。如果您必须同时对树进行多个更改,则上述解决方案可作为标记待修改节点的通用方法。谢谢@Tamas SonarSourceTeam。我根据你的建议更新了你的答案,以防将来对任何人都有帮助。感谢您的帮助,很抱歉我花了这么长时间才回到这里。对于我来说,如果没有任何用法,newRoot=newRoot.InsertNodesBefore
或newRoot=newRoot.InsertNodesAfter
不起作用。我使用了newRoot=compilationUnit.AddUsings(usingDirective)代码>