如何在C#增量源生成器中访问编译时配置与常量?
问题
我采用增量生成器方式编写C#源生成器,希望允许开发者通过两种方式控制额外代码(如注释、调试输出、严格校验等)的生成:一是在使用该生成器的项目.csproj中添加DefineConstants;二是通过dotnet build命令行的-p参数。我查看了IncrementalGeneratorInitializationContext、SourceProductionContext、Compilation等类型,未找到相关访问方式。目前的替代方案是使用自定义属性,但需要开发者手动多次添加,请问是否有办法在增量生成器工作流中访问这两类编译时设置?
解决方案
当然可以访问这两类编译时设置,核心是利用Compilation对象的编译选项获取常量,以及通过AnalyzerConfigOptionsProvider读取项目级MSBuild属性(包括命令行传入的-p参数)。
1. 访问DefineConstants编译常量
在增量生成器的处理逻辑中,你可以通过Compilation.Options拿到CSharpCompilationOptions,进而直接获取DefineConstants集合:
// 在增量生成器的节点处理逻辑中 var hasDebugOutput = compilation.Options.DefineConstants.Contains("GENERATOR_DEBUG_OUTPUT"); var enableStrictValidation = compilation.Options.DefineConstants.Contains("GENERATOR_STRICT_VALIDATION");
开发者只需通过两种方式传入常量:
- 在项目.csproj中配置:
<PropertyGroup> <DefineConstants>$(DefineConstants);GENERATOR_DEBUG_OUTPUT;GENERATOR_STRICT_VALIDATION</DefineConstants> </PropertyGroup>
- 或者通过命令行传入:
dotnet build -p:DefineConstants="GENERATOR_DEBUG_OUTPUT;GENERATOR_STRICT_VALIDATION"
生成器读取到这些常量后,即可根据判断结果控制代码生成逻辑。
2. 访问MSBuild属性(含命令行-p参数)
增量生成器可以通过IncrementalGeneratorInitializationContext注册AnalyzerConfigOptionsProvider作为数据源,以此获取项目级的MSBuild属性:
步骤1:注册数据源并读取配置
public void Initialize(IncrementalGeneratorInitializationContext context) { // 注册全局配置作为数据源 var globalConfig = context.AnalyzerConfigOptionsProvider.Select((provider, _) => provider.GlobalOptions); // 将配置与你需要处理的语法节点关联 var combinedData = context.SyntaxProvider .CreateSyntaxProvider(/* 你的语法筛选逻辑 */) .Combine(globalConfig); // 注册代码生成逻辑 context.RegisterSourceOutput(combinedData, (spc, data) => { var (targetNode, options) = data; // 读取项目中配置的自定义属性 if (options.TryGetValue("build_property.Generator_EnableComments", out var enableCommentsStr) && bool.TryParse(enableCommentsStr, out var enableComments)) { // 根据配置生成带注释的代码 } // 读取命令行传入的-p参数(比如dotnet build -p:Generator_DebugMode=true) if (options.TryGetValue("build_property.Generator_DebugMode", out var debugModeStr) && bool.TryParse(debugModeStr, out var debugMode)) { // 生成调试输出相关代码 } }); }
步骤2:开发者配置方式
- 在项目.csproj中添加:
<PropertyGroup> <Generator_EnableComments>true</Generator_EnableComments> <Generator_DebugMode>false</Generator_DebugMode> </PropertyGroup>
- 或者通过命令行直接传入:
dotnet build -p:Generator_EnableComments=true -p:Generator_DebugMode=true
注意事项
AnalyzerConfigOptionsProvider.GlobalOptions中,MSBuild属性的键格式为build_property.{属性名},注意属性名大小写需与项目配置一致。- 增量生成器读取的配置是编译时静态值,不会随代码修改动态变化,符合增量生成器的工作机制。
- 如果需要区分不同文件/项目的配置,可使用
AnalyzerConfigOptionsProvider.GetOptions(SyntaxNode)获取特定节点所在项目的配置,大部分场景下GlobalOptions已足够使用。
内容的提问来源于stack exchange,提问作者sanelli
相关产品推荐
相关产品推荐

