Source Generator 是编译前期生成 .cs 文件的工具,不修改已有类、不运行时逻辑、不替代反射或 DI;常见失效原因是未正确引用生成器项目或未启用 EmitCompilerGeneratedFiles。
Source Generator 不是编译时“魔法”,它不能修改已有类行为、不能生成运行时逻辑、也不能替代反射或 DI;它只在 C# 编译前期(semantic model 可用后)生成 .cs 文件并参与后续编译——理解这点,才能避开 90% 的误用和报错。
为什么
实现后没生效?
最常见原因是未正确引用生成器项目,或未启用生成器支持。SDK 风格项目默认不自动包含 generator 引用,且需要显式启用
特性感知。
确保 consuming 项目(即使用生成器的项目)的
中包含:
必须在 consuming 项目的
中添加:
否则即使生成成功,你也看不到输出文件,调试无从下手
VS 中需关闭“仅我的代码”并在调试器中手动加载生成的
文件(路径见
),否则断点不会命中
如何安全读取用户代码中的
并生成对应类?
不能直接 new Attribute 实例——Source Generator 运行时没有运行环境,所有 attribute 数据必须通过
或
提前捕获语法节点,再用
获取语义符号。
C知道
CSDN推出的一款AI技术问答工具
下载
推荐用
(.NET 6+):在
前就完成语法筛选,避免每次遍历全 AST
匹配
时,要检查
而非字符串比较,防止别名或 using 冲突
生成类名时务必调用
+
拼接,否则跨命名空间会生成重复类名
不要尝试生成
的另一部分去注入字段——C# 编译器要求所有 partial 定义必须在同一编译单元可见,而 generator 输出是后置加入的,会导致 CS0260 错误
比传统
快在哪?
核心差异在于增量计算:
用
链描述数据流,编译器可跳过未变更输入对应的生成步骤;传统方式每次全量执行
,哪怕只改了一个字符。
必须用
注册初始化输出(如 global usings)
关键链路示例:
其中
必须极轻量(只看语法树节点类型/Kind),重逻辑必须放到
或后续
若在
中调用
,必须用
当前实例,不能缓存旧 compilation —— 否则增量模式下会拿到过期符号
VS 中启用
后重试,可排除 IDE 缓存干扰;真实提速需配合大解决方案(>50 个项目)才明显
真正难的不是写对第一个
,而是当它被用于生成序列化注册、DTO 映射或路由表时,如何让错误信息指向用户代码而非 generator 内部——这要求你在
里精确绑定
到原始语法节点,而不是随便打个
。
ISourceGeneratorCompilerGenerated.csproj
.csproj
true
obj/Generated
*.g.csCompilerGeneratedFilesOutputPath[Attribute]SyntaxReceiverISyntaxContextReceiversemanticModel.GetSymbolInfo()ISyntaxContextReceiverExecute[MyAutoNotify]attributeData.AttributeClass?.ToDisplayString()INamedTypeSymbol.ContainingNamespace.ToDisplayString()namepartial classIncrementalGeneratorISourceGeneratorIncrementalGeneratorProviderExecutecontext.RegisterPostInitializationOutputvar candidates = context.SyntaxProvider
.CreateSyntaxProvider((s, _) => IsCandidate(s), TransformSyntax);
var models = candidates.Collect();
context.RegisterSourceOutput(models, GenerateFromModels);IsCandidateTransformSyntaxGenerateFromModelsTransformSyntaxsemanticModel.GetDeclaredSymbol()context.Compilationdotnet build-server shutdownSourceGeneratorReportDiagnosticLocation.Create()Location.None