Roslyn SemanticModel符号解析异常:标准库方法调用无法识别符号
问题
编写C#代码分析程序时,使用Roslyn的CSharpSyntaxTree和SemanticModel识别方法调用对应的类和方法,但符号解析效果不稳定,多数场景失败。例如解析标准库静态方法Environment.Exit(0)时,无法找到任何候选符号。
测试分析代码:
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; class Program { static void Main(string[] _) { var compilation = CSharpCompilation.Create("MyCompilation") .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication)) .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), MetadataReference.CreateFromFile(typeof(Environment).Assembly.Location), MetadataReference.CreateFromFile(Path.Combine( Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll"))); var file = "Class1.cs"; var tree = CSharpSyntaxTree.ParseText(File.ReadAllText(file), CSharpParseOptions.Default, file); if (tree.GetDiagnostics().Any()) { foreach (var diagnostic in tree.GetDiagnostics()) Console.Error.WriteLine(diagnostic); Environment.Exit(1); } compilation = compilation.AddSyntaxTrees(tree); var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); new Walker(model).Visit(root); } } class Walker: CSharpSyntaxWalker { public Walker(SemanticModel model) { this.model = model; } public override void VisitInvocationExpression(InvocationExpressionSyntax node) { base.VisitInvocationExpression(node); var symbolInfo = model.GetSymbolInfo(node); Console.WriteLine(node); Console.WriteLine(symbolInfo.Symbol); Console.WriteLine(symbolInfo.CandidateSymbols.ToArray()); } readonly SemanticModel model; }
测试目标代码(Class1.cs):
class Class1 { void Method1() { Environment.Exit(0); } }
运行输出:
Environment.Exit(0) Microsoft.CodeAnalysis.ISymbol[]
解决方案
- 缺少命名空间引用:目标代码里的
Environment属于System命名空间,但Class1.cs没有添加using System;,语义分析无法识别该类型。 - 未检查编译诊断:仅检查了语法树的语法错误,但添加语法树到编译后,可能存在编译级错误(如找不到类型),这类错误会直接导致语义模型无法解析符号。
修复步骤
- 给目标代码
Class1.cs添加命名空间引用:
using System; class Class1 { void Method1() { Environment.Exit(0); } }
- 在分析代码中添加编译诊断检查,确保编译无错误:
在compilation = compilation.AddSyntaxTrees(tree);之后插入:
var compilationDiagnostics = compilation.GetDiagnostics(); if (compilationDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) { foreach (var diagnostic in compilationDiagnostics) Console.Error.WriteLine(diagnostic); Environment.Exit(1); }
- 优化符号输出逻辑,避免直接输出数组类型名:
修改Walker类的VisitInvocationExpression方法:
public override void VisitInvocationExpression(InvocationExpressionSyntax node) { base.VisitInvocationExpression(node); var symbolInfo = model.GetSymbolInfo(node); Console.WriteLine(node); Console.WriteLine(symbolInfo.Symbol ?? "No symbol found"); Console.WriteLine("Candidate symbols:"); foreach (var candidate in symbolInfo.CandidateSymbols) Console.WriteLine($" - {candidate}"); }
修改后的完整分析代码
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.IO; class Program { static void Main(string[] _) { var compilation = CSharpCompilation.Create("MyCompilation") .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication)) .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), MetadataReference.CreateFromFile(typeof(Environment).Assembly.Location), MetadataReference.CreateFromFile(Path.Combine( Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll"))); var file = "Class1.cs"; var tree = CSharpSyntaxTree.ParseText(File.ReadAllText(file), CSharpParseOptions.Default, file); if (tree.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) { foreach (var diagnostic in tree.GetDiagnostics()) Console.Error.WriteLine(diagnostic); Environment.Exit(1); } compilation = compilation.AddSyntaxTrees(tree); // 检查编译诊断 var compilationDiagnostics = compilation.GetDiagnostics(); if (compilationDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) { foreach (var diagnostic in compilationDiagnostics) Console.Error.WriteLine(diagnostic); Environment.Exit(1); } var model = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); new Walker(model).Visit(root); } } class Walker: CSharpSyntaxWalker { public Walker(SemanticModel model) { this.model = model; } public override void VisitInvocationExpression(InvocationExpressionSyntax node) { base.VisitInvocationExpression(node); var symbolInfo = model.GetSymbolInfo(node); Console.WriteLine(node); Console.WriteLine(symbolInfo.Symbol ?? "No symbol found"); Console.WriteLine("Candidate symbols:"); foreach (var candidate in symbolInfo.CandidateSymbols) Console.WriteLine($" - {candidate}"); } readonly SemanticModel model; }
修复后运行,会正确输出:
Environment.Exit(0) void System.Environment.Exit(int exitCode) Candidate symbols: - void System.Environment.Exit(int exitCode)
内容的提问来源于stack exchange,提问作者rwallace
相关产品推荐
相关产品推荐

