源生成器中调用GetSymbolInfo获取属性时返回null问题排查
源生成器中
info.Symbol始终为null的解决方法 核心问题分析
你遇到的info.Symbol为null的情况,本质是语法节点的语义绑定不完整,或是符号匹配的方式不对——哪怕属性的语法节点能被识别,缺少完整编译上下文或错误的符号对比逻辑,都会导致无法获取到对应的INamedTypeSymbol。
以下是针对性的解决步骤:
1. 改用类的语义符号直接匹配属性
遍历语法节点的属性再查语义的方式容易出错,直接获取类的语义符号后检查属性,可靠性更高:
修改你的GetSemanticTargetForGeneration方法:
private static ClassDeclarationSyntax? GetSemanticTargetForGeneration(GeneratorSyntaxContext context) { if (context.Node is not ClassDeclarationSyntax classDeclaration) return null; // 先获取类的语义符号,确保类本身已被正确绑定 if (context.SemanticModel.GetDeclaredSymbol(classDeclaration) is not INamedTypeSymbol classSymbol) return null; // 通过元数据名称提前拿到目标属性的符号(避免引用路径导致的匹配问题) var targetAttrSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("LaMP.API.RepositoryAttribute"); if (targetAttrSymbol == null) return null; // 用官方推荐的符号比较器检查属性是否匹配 foreach (var attribute in classSymbol.GetAttributes()) { if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, targetAttrSymbol)) { // 匹配到目标属性,返回类语法节点 return classDeclaration; } } return null; }
这里用SymbolEqualityComparer.Default是关键——它会忽略程序集引用的差异,只对比类型的元数据本质,避免因重复引用导致的符号不匹配。
2. 补全测试编译的基础引用
你的测试代码只添加了属性所在的程序集,但缺少.NET基础类库的引用,会导致编译上下文不完整,语义分析失败。修改测试的Verify方法:
public static Task Verify(string source) { var syntaxTree = CSharpSyntaxTree.ParseText(source); // 添加基础类库引用(比如System.Runtime) var coreLibRef = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); var attrAssemblyRef = MetadataReference.CreateFromFile(typeof(LaMP.API.RepositoryAttribute).Assembly.Location); var references = new List<PortableExecutableReference> { coreLibRef, attrAssemblyRef // 如果属性依赖其他程序集(比如System.ComponentModel),也要一并添加 }; // 指定编译输出类型为类库,更贴近实际项目场景 var compilation = CSharpCompilation.Create( "Test", new[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var target = CSharpGeneratorDriver.Create(new RepositorySourceGenerator()).RunGenerators(compilation); return Verifier .Verify(target) .UseDirectory("Snapshots"); }
3. 检查属性的访问权限
如果RepositoryAttribute是internal访问修饰符,需要在属性所在程序集的AssemblyInfo.cs中添加特性,允许测试项目访问内部类型:
[assembly: InternalsVisibleTo("你的测试项目名称")]
内容的提问来源于stack exchange,提问作者Gargoyle
相关产品推荐
相关产品推荐

