我正在尝试修改语法树,然后更新语义模型。以下是我到目前为止的情况:
var tree = Roslyn.Compilers.CSharp.SyntaxTree.ParseCompilationUnit(code);
var compilation = Roslyn.Compilers.CSharp.Compilation.Create(
"MyCompilation",
syntaxTrees: new[] { tree },
references: new[] { mscorlib });
var semanticModel = compilation.GetSemanticModel(tree);
...
var oldStatementNode = (parent as ExpressionStatementSyntax); //some SyntaxNode in the tree
var oldExpressionNode = oldStatementNode.Expression;
var newExpressionNode = Syntax.ParenthesizedExpression(oldExpressionNode);
var newRootNode = tree.GetRoot().ReplaceNode(oldExpressionNode, newExpressionNode);
var semanticInfo = semanticModel.GetTypeInfo(newExpressionNode); //throws exception "Syntax node is not within syntax tree"
如果我在调用semanticModel = compilation.GetSemanticModel(tree);
之前尝试调用tree
或甚至使用GetTypeInfo()
进行新编译 - 同样的例外。
那么如何更新SemanticModel
?
(当然我可以修改源代码并从头开始做所有事情,但我想有更有效的方法)。
我遗漏了一些显而易见的东西我敢肯定,或许在某处创建了一个新的语法树?
答案 0 :(得分:15)
Roslyn类型是不可变的,因此您需要为SyntaxTree
构建一个新的newRootNode
,然后调用compilation.UpdateSyntaxTree
以获取新的Compilation
,然后您就可以了致电newCompilation.GetSemanticModel(newTree)
以获取新的SemanticModel
。
考虑升级到服务级别并改为使用ISolution。类似的东西:
var doc = Solution.Create(SolutionId.CreateNewId()).AddCSharpProject("MyCompilation", "MyCompilation").AddMetadataReference(mscorlib).AddDocument("MyFile", code);
var semanticModel = (SemanticModel)doc.GetSemanticModel();
var root = (CompilationUnitSyntax)doc.GetSyntaxRoot();
SyntaxNode parent = null;
var oldStatementNode = (parent as ExpressionStatementSyntax); //some SyntaxNode in the tree
var oldExpressionNode = oldStatementNode.Expression;
var newExpressionNode = Syntax.ParenthesizedExpression(oldExpressionNode);
var newRootNode = root.ReplaceNode(oldExpressionNode, newExpressionNode);
doc = doc.UpdateSyntaxRoot(newRootNode);
semanticModel = (SemanticModel)doc.GetSemanticModel();