我有一些逻辑,可以使用Roslyn向类添加函数,该函数适用于C#项目,但不适用于VB项目。我正在使用DocumentEditor编辑器类(Microsoft.CodeAnalysis.Editing.DocumentEditor)执行更新。
我首先找到与类定义相对应的SyntaxNode。
在C#中,这是一个[[ClassDeclarationSyntax元素。
在VB中,这是
ClassBlockSyntax
元素。我在字符串变量中生成新函数的完整文本,然后从该文本创建SyntaxNode。
对于C#,我使用方法
CSharpSyntaxTree.ParseText
,大致如下:var Tree = CSharpSyntaxTree.ParseText ( Code, CSharpParseOptions.Default ) ;
var Root = await Tree.GetRootAsync() as CompilationUnitSyntax ;
var Expr = Root.Members.FirstOrDefault()
.WithAdditionalAnnotations ( Formatter.Annotation ) ;
然后,Expr的类型为。对于VB,我使用方法MethodDeclarationSyntax
VisualBasicSyntaxTree.ParseText
,其代码几乎相同:var Tree = VisualBasicSyntaxTree.ParseText ( Code ) ;
var Root = await Tree.GetRootAsync() as CompilationUnitSyntax ;
var Expr = Root.Members.FirstOrDefault() ;
在这种情况下,Expr的类型为。然后我尝试将新节点插入类。MethodBlockSyntax
对于C#,我使用
RoslynDocEditor.InsertAfter ( RoslynClass.ChildNodes.Last, Expr )
其中RoslynClass是ClassBlockSyntax节点,以及稍后……
RootNode = RoslynDocEditor.GetChangedRoot() RootNode = Formatter.Format ( RootNode, Formatter.Annotation, VSWorkspace ) RoslynDoc = RoslynDoc.WithSyntaxRoot ( RootNode ) ApplyOK = VSWorkspace.TryApplyChanges ( RoslynDoc.Project.Solution )
这将在类末尾添加新功能。如果我对VB进行同样的操作,则会在该行生成
InvalidOperationException
RootNode = RoslynDocEditor.GetChangedRoot()
带有描述“指定的项目不是列表的元素”和堆栈跟踪:
at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.NodeListEditor.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.VisitClassBlock(ClassBlockSyntax node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.ClassBlockSyntax.Accept[TResult](VisualBasicSyntaxVisitor`1 visitor) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.BaseListEditor.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.NodeListEditor.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.VisitListElement[TNode](TNode node) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.VisitList[TNode](SyntaxList`1 list) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.NodeListEditor.VisitList[TNode](SyntaxList`1 list) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.VisitCompilationUnit(CompilationUnitSyntax node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.CompilationUnitSyntax.Accept[TResult](VisualBasicSyntaxVisitor`1 visitor) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxRewriter.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.BaseListEditor.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.NodeListEditor.Visit(SyntaxNode node) at Microsoft.CodeAnalysis.VisualBasic.Syntax.SyntaxReplacer.InsertNodeInList(SyntaxNode root, SyntaxNode nodeInList, IEnumerable`1 nodesToInsert, Boolean insertBefore) at Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode.InsertNodesInListCore(SyntaxNode nodeInList, IEnumerable`1 nodesToInsert, Boolean insertBefore) at Microsoft.CodeAnalysis.SyntaxNodeExtensions.InsertNodesBefore[TRoot](TRoot root, SyntaxNode nodeInList, IEnumerable`1 newNodes) at Microsoft.CodeAnalysis.VisualBasic.CodeGeneration.VisualBasicSyntaxGenerator.InsertDeclarationsBeforeInternal(SyntaxNode root, SyntaxNode declaration, IEnumerable`1 newDeclarations) at Microsoft.CodeAnalysis.VisualBasic.CodeGeneration.VisualBasicSyntaxGenerator._Closure$__310-0._Lambda$__0(SyntaxNode r) at Microsoft.CodeAnalysis.Editing.SyntaxGenerator.PreserveTrivia[TNode](TNode node, Func`2 nodeChanger) at Microsoft.CodeAnalysis.VisualBasic.CodeGeneration.VisualBasicSyntaxGenerator.InsertNodesBefore(SyntaxNode root, SyntaxNode declaration, IEnumerable`1 newDeclarations) at Microsoft.CodeAnalysis.Editing.SyntaxEditor.InsertChange.Apply(SyntaxNode root, SyntaxGenerator generator) at Microsoft.CodeAnalysis.Editing.SyntaxEditor.GetChangedRoot() at MultiLang.frmLanguageSwitching.VB$StateMachine_133_btAdd_Click.MoveNext() in C:\VSPackage_Version_7_1\Project\MultiLang\Forms\frmLanguageSwitching.vb:line 944
从语法可视化器的屏幕快照中,您可以看到ClassBlock的最后一个子元素是,因此使用起来更有意义EndClassStatement
RoslynDocEditor.InsertBefore ( RoslynClass.ChildNodes.Last, NewFunctionNode )
但是会产生与上面完全相同的错误。是否可以通过类似的方式在VB类中插入函数,或者仅在C#中有效?
SyntaxNode(返回)转换为ClassBlockSyntax,然后使用Members集合
var cbs = ClassNode as Microsoft.CodeAnalysis.VisualBasic.Syntax.ClassBlockSyntax ;
RoslynDocEditor.InsertAfter ( cbs.Members.Last(), Expr ) ;
如果我将ClassNode强制转换为,则对C#同样有效”>ClassDeclarationSyntax
var cds = ClassNode as Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax ;
RoslynDocEditor.InsertAfter ( cds.Members.Last(), NewFunction ) ;
但如上所述,对于C#,它也可以与]一起使用>
RoslynDocEditor.InsertAfter ( RoslynClass.ChildNodes.Last, NewFunction ) ;
所以看起来,但不等同于VB的ClassBlockSyntax.Members。SyntaxNode.ChildNodes
等同于C#的ClassDeclarationSyntax.Members