调用Roslyn的INamedTypeSymbol.GetMembers()时触发找不到方法异常
INamedTypeSymbol.GetMembers()抛出异常的问题 看起来你遇到的情况挺有意思——代码里调用classReference.GetMembers()直接炸了,但调试即时窗口里却能正常返回结果。结合你用Roslyn定位方法的场景,我给你几个排查和解决的方向:
1. 先确认classReference的有效性
首先得确保classReference是正常可用的INamedTypeSymbol实例,不是未初始化、已失效或者来自错误上下文的符号。可以在调用GetMembers()前加个简单的检查:
if (classReference is INamedTypeSymbol namedType && namedType.IsValid) { var members = namedType.GetMembers(); // 后续处理逻辑 } else { Debug.WriteLine($"异常:classReference状态异常,类型为{classReference?.GetType().Name}"); }
有时候异步方法里的变量捕获可能会导致符号状态异常,而即时窗口是即时求值,会重新拉取最新的符号状态,所以能正常工作。
2. 确保依赖正确的语义模型
Roslyn的符号操作完全依赖语义模型(SemanticModel),如果你的classReference是从语法节点获取的,一定要用正确的方式获取:
// 正确从语法节点提取类型符号的示例 var classSyntax = root.DescendantNodes() .OfType<ClassDeclarationSyntax>() .First(c => c.Identifier.Text == className); var classSymbol = semanticModel.GetDeclaredSymbol(classSyntax);
如果classReference是通过符号查找、元数据引用等方式获取的,也要确保对应的语义模型或元数据已完整加载,避免符号处于未解析状态。
3. 避开async void的上下文陷阱
你的方法是async void,这种方法的执行上下文和异常处理逻辑和async Task差异很大。有可能你调用GetMembers()时,Roslyn的后台加载操作还没完成,但即时窗口会等待操作完成再求值。建议把方法改成async Task,确保所有依赖的Roslyn异步操作都完成后再处理符号:
public async Task NavigateToMethod(string className, string methodName) { // 确保文档、语义模型等异步加载操作完成 var document = await workspace.OpenDocumentAsync(...); var semanticModel = await document.GetSemanticModelAsync(); // 获取classReference的逻辑 if (classReference is INamedTypeSymbol namedType) { var targetMethods = namedType.GetMembers(methodName).OfType<IMethodSymbol>(); // 定位方法的后续逻辑 } }
async void更适合事件处理,不适合有后续依赖的业务逻辑,改成async Task能更好地控制执行流程。
4. 直接定位目标方法(更高效)
既然你已经知道方法名,没必要先获取所有成员再筛选,直接用带参数的GetMembers(string name)重载,既高效又能避免通用枚举可能遇到的异常:
// 直接获取指定名称的方法符号,还能处理重载情况 var targetMethods = classReference.GetMembers(methodName).OfType<IMethodSymbol>(); foreach (var method in targetMethods) { // 根据方法的参数、返回值等筛选出你要的目标方法 }
内容的提问来源于stack exchange,提问作者rxx

