Как вставить функцию в класс в VB. NET, используя Roslyn - PullRequest
0 голосов
/ 18 февраля 2020

У меня есть логика c для добавления функции в класс с помощью Roslyn, которая работает с проектом C#, но не с проектом VB. Я использую DocumentEditor класс редактора ( Microsoft.CodeAnalysis.Editing.DocumentEditor ) для выполнения обновления.

Я начинаю с поиска SyntaxNode соответствует определению класса.

В C# это элемент ClassDeclarationSyntax .

Screenshot of Syntax Visualizer for VB class

В VB это ClassBlockSyntax element.

Screenshot of Syntax Visualizer for VB class

Я генерирую полный текст новой функции в строковой переменной, а затем создаю 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 имеет тип MethodDeclarationSyntax .

Для VB я использую метод 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#.

1 Ответ

0 голосов
/ 22 февраля 2020

Это работает для VB, если я приведу ClassNode от SyntaxNode (назад) к ClassBlockSyntax , а затем использую Members collection

var cbs = ClassNode as Microsoft.CodeAnalysis.VisualBasic.Syntax.ClassBlockSyntax ;
RoslynDocEditor.InsertAfter ( cbs.Members.Last(), Expr ) ;

То же самое работает для C#, если я приведу ClassNode к ClassDeclarationSyntax

var cds = ClassNode as Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax ;
RoslynDocEditor.InsertAfter ( cds.Members.Last(), Expr ) ;

, но, как уже описано, для C# он также работает с

RoslynDocEditor.InsertAfter ( RoslynClass.ChildNodes.Last, Expr ) ;

Так выглядит SyntaxNode.ChildNodes эквивалентно ClassDeclarationSyntax.Members для C#, но не эквивалентно ClassBlockSyntax.Members для VB.


РЕДАКТИРОВАТЬ

Похоже, проще и лучше использовать метод расширения AddMember :

RoslynDocEditor.AddMember ( RoslynClass, expr )
...