在我的Visual Studio扩展中,我使用DocumentEditor(Microsoft.CodeAnalysis.Editing.DocumentEditor)类对源文件进行多次更新。
其中一个更改是将构造函数添加到类中。构造函数必须具有特定参数,该参数由依赖项注入传入,并且必须将参数保存到成员变量。如果构造函数已存在,则应检查参数并检查赋值语句。
其中大部分工作正常,但如果我必须向空函数添加语句,则会出现问题。
如果构造函数已经存在并包含一些语句,我可以添加一个新语句
RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;
如果构造函数存在但是为空,那么这将不起作用。到目前为止,我还没有找到任何方法使用DocumentEditor类将语句插入到空函数体中。
目前,我选择了使用DocumentEditor.ReplaceNode替换完整构造函数的大锤方法。
那么有没有办法在函数体中插入一个语句 - 使用DocumentEditor类 - 如果正文是空的?
这是我的代码的一部分。 _RoslynUtilCS中的函数只返回一些roslyn语法。
// Look for the constructor
var cons = c.DescendantNodes().OfType<ConstructorDeclarationSyntax>().FirstOrDefault() ;
if ( cons == null )
{
// There is no constructor.
cons = _RoslynUtilCS.ControllerConstructor ( ShortClassName )
.WithAdditionalAnnotations ( Formatter.Annotation )
.WithTrailingTrivia ( _RoslynUtilCS.LineFeedSyntax() ) ;
RoslynEditor.InsertBefore ( c.Members.First(), cons ) ;
}
else
{
string parameterName = null ;
// There is a constructor.
// Does it already have a parameter of the generic IStringLocalizer type
foreach ( var p in cons.ParameterList.Parameters )
{
var t = p.Type ;
var gt = t as GenericNameSyntax ;
if ( gt != null )
{
if ( gt.Identifier.ToString() == "IStringLocalizer" )
{
parameterName = p.Identifier.ToString() ;
}
}
}
if ( string.IsNullOrEmpty ( parameterName ) )
{
// Add a parameter
var param = _RoslynUtilCS.LocalizerParameter ( ShortClassName ) ;
RoslynEditor.AddParameter ( cons, param ) ;
// Add an assignment statement to assign the parameter to the localizer member variable.
var assExpr = _RoslynUtilCS.LocalizerAsignment()
.WithAdditionalAnnotations ( Formatter.Annotation ) ;
if ( cons.Body.Statements.Count == 0 )
{
// -------------------------------------------------------------------
// Here I replace the complete constructor.
// because I don't know how to insert a statement into
// the empty constructor body.
// -------------------------------------------------------------------
var newcons = _RoslynUtilCS.ControllerConstructor ( ShortClassName )
.WithAdditionalAnnotations ( Formatter.Annotation )
.WithTrailingTrivia ( _RoslynUtilCS.LineFeedSyntax() ) ;
RoslynEditor.ReplaceNode ( cons, newcons ) ;
}
else
{
RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;
}
}
else
{
// NOT TESTED
// It seems a bit over the top, but having found a parameter, we should look
// for an assignment to the member variable and add it if it is missing.
var count = cons.DescendantNodes()
.OfType<AssignmentExpressionSyntax>()
.Where(node => node.Kind() == SyntaxKind.SimpleAssignmentExpression)
.Where(node => node.Left.ToString() == "_localizer")
.Where(node => node.Right.ToString() == "localizer")
.Count() ;
if ( count == 0 )
{
// Add an assignment statement to assign the parameter to the localizer member variable.
var assExpr = _RoslynUtilCS.LocalizerAsignment() ;
// -------------------------------------------------------------------
// This is likely to have the same problem.
// It won't work if the body contains no statements.
// -------------------------------------------------------------------
RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;
}
}
}
编辑的Insert
和Add
方法最终是InsertMembers
的SyntaxGenerator
,他们无论如何用新的AKA Replace
替换原始节点。
检查这个方法的source code,你会看到插入成员阻塞正文有0个成员(如果是ConstructorDeclarationSyntax
)返回声明本身没有变化,这就是为什么你不能做简单的editor.Insert\Add..
。
您可以定义一个新的扩展方法,为您执行此操作,或者编写类似于替换正文的内容:
editor.ReplaceNode(ctor.Body, SyntaxFactory.Block(newStatement));
要么
editor.ReplaceNode(ctor, ctor.WithBody(ctor.Body.AddStatements(newStatement)));