Source Generator 不会自动生效,需项目配置、引用方式、接口实现和执行路径四者全部对齐;最常见失效原因是 Roslyn 未识别生成器,根源在于宿主项目未正确声明带 OutputItemType="Analyzer" 和 ReferenceOutputAssembly="false" 的 ProjectReference。

Source Generator 不会自动生效,哪怕代码写得完全正确——它依赖项目配置、引用方式、接口实现和执行路径四个环节全部对齐,缺一不可。
为什么 Execute 方法根本没被调用
最常见原因是 Roslyn 根本没“看到”你的生成器。这通常不是代码问题,而是宿主项目没正确声明 analyzer 引用。
-
ProjectReference必须带两个属性:OutputItemType="Analyzer"和ReferenceOutputAssembly="false";只加普通引用或 NuGet 包引用都不行 - 目标项目必须是 SDK 风格项目(
<Project Sdk="Microsoft.NET.Sdk">),且<TargetFramework>是net5.0或更高(netstandard2.0不支持) - 生成器项目自身需设
<IsAnalyzer>true</IsAnalyzer>,并以netstandard2.0为目标框架(兼容性最佳) -
[Generator]特性必须来自Microsoft.CodeAnalysis命名空间,手误写成自定义同名特性或漏引用Microsoft.CodeAnalysis.CSharpNuGet 包,就会静默失效
用 IIncrementalGenerator 而不是 ISourceGenerator
ISourceGenerator 已被标记为过时,全量执行模式会让构建速度随代码量线性下降;IIncrementalGenerator 是唯一推荐路径,靠显式声明依赖项来启用增量计算。
- 在
Initialize中不能做任何耗时操作或副作用,只允许注册管道(如context.SyntaxProvider.CreateSyntaxProvider()) - 过滤语法节点必须用
CreateSyntaxProvider,比如只处理带[AutoNotify]的属性,而不是在Execute里遍历所有SyntaxTree - 语义模型必须通过
context.CompilationProvider获取,不能在语法过滤阶段调用GetSemanticModelAsync() - 最终必须链式调用
.Select().Collect().SelectMany().RegisterSourceOutput(),断掉任一环都会退化为全量执行
生成的代码不参与编译或报 CS0260 错误
生成的类型无法被识别,或出现 CS0260: Partial declarations must be in the same compilation unit,说明生成逻辑违反了 C# 编译约束。
- 生成的文件名必须以
.g.cs结尾(如"MyViewModel.g.cs"),否则可能和手写文件冲突或被 IDE 忽略 - 不能尝试用生成器去补全
partial class的另一部分字段——C# 要求所有partial定义在同一编译单元可见,而 generator 输出是后置注入的 - 生成类名时,务必用
INamedTypeSymbol.ContainingNamespace.ToDisplayString()拼接,硬编码命名空间会导致跨命名空间重复定义 - 生成内容必须是合法 C# 语法,且不能引用尚未生成的类型;若需依赖用户代码中的类型,必须通过
semanticModel.GetSymbolInfo()获取符号,而非字符串匹配
调试时看不到生成的 .g.cs 文件
即使生成成功,VS 默认也不会显示这些文件,导致断点不命中、无法检查输出内容。
- 必须在宿主项目的
.csproj中显式启用:<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>和<CompilerGeneratedFilesOutputPath>obj/Generated</CompilerGeneratedFilesOutputPath> - VS 中需关闭“仅我的代码”(Tools → Options → Debugging → General → “Enable Just My Code”),否则调试器不会加载
obj/Generated下的文件 - 生成的文件实际路径是
obj/Generated/YourGeneratorName/FileName.g.cs,可直接用文件管理器打开验证内容 - 不要在
Execute中throw new Exception(),这会让整个编译失败;改用context.ReportDiagnostic()发送诊断信息,它会在错误列表中显示
最容易被忽略的是增量管道的链式完整性:从 CreateSyntaxProvider 到 RegisterSourceOutput 中间任何一个 Select 或 Collect 没接上,都会让整个生成器退化为每次全量执行——性能损耗在中大型项目里几乎是不可接受的。


















