You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从生成代码触发C# JSON源代码生成器执行?

问题:如何让自定义增量生成器生成的代码触发System.Text.Json源代码生成器单次构建成功

我实现了一个增量源代码生成器,可生成符合System.Text.Json源代码生成器要求的WeatherJsonContext类,但当前必须执行两次构建才能成功:第一次构建时自定义生成器输出代码,但编译器会报“WeatherJsonContext未实现继承的抽象成员”错误;第二次构建时Json源代码生成器才会执行,最终构建成功。需要实现单次构建完成整个流程。


自定义生成器代码

namespace ClassJsonGen;

using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

[Generator]
public class CustomGenerator : IIncrementalGenerator
{
    private const string TestSource = @"
            namespace WebJsonGen {
                using System.Text.Json.Serialization;
                [JsonSerializable(typeof(IEnumerable<WeatherForecast>))]
                [JsonSerializable(typeof(IEnumerable<StormForecast>))]
                public partial class WeatherJsonContext : JsonSerializerContext
                { } 
            }";

    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
#if DEBUG
        if (!Debugger.IsAttached)
        {
            Debugger.Launch();
        }
#endif

        var todoInput = context.SyntaxProvider
            .CreateSyntaxProvider(
                predicate: static (s, _) => s is ClassDeclarationSyntax,
                transform: static (ctx, _) => ctx.Node)
            .Where(static m => m is not null);

        context.RegisterSourceOutput(todoInput, (ctx, inp) =>
        {
            // TODO use input to determine which [JsonSerializable] we need :-)
            ctx.AddSource("JSON.g.cs", SourceText.From(TestSource, Encoding.UTF8));
        });
    }
}

生成的代码

namespace WebJsonGen {
    using System.Text.Json.Serialization;
    [JsonSerializable(typeof(IEnumerable<WeatherForecast>))]
    [JsonSerializable(typeof(IEnumerable<StormForecast>))]
    public partial class WeatherJsonContext : JsonSerializerContext
    { } 
}

消费项目的.csproj配置

<PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>

    <ItemGroup>
        <!-- Exclude the output of source generators from the compilation -->
        <Compile Remove="$(CompilerGeneratedFilesOutputPath)/System.Text.Json.SourceGeneration/**/*.cs" />
        <Compile Include="$(CompilerGeneratedFilesOutputPath)/System.Text.Json.SourceGeneration/**/JSON*.cs" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassJsonGen\ClassJsonGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    </ItemGroup>

解决方法

问题核心是源代码生成器的执行顺序:自定义生成器与System.Text.Json生成器默认并行执行,Json生成器无法在同一轮构建中识别到刚生成的WeatherJsonContext类,导致第一次构建报错。以下两种方案可实现单次构建完成:

方案1:使用RegisterPostInitializationOutput输出代码

将生成WeatherJsonContext的逻辑移至RegisterPostInitializationOutput方法,该方法会在所有生成器初始化完成、主编译分析前执行,输出的代码会被纳入初始编译流程,让Json生成器在同一轮构建中就能识别到目标类。

修改自定义生成器的Initialize方法:

public void Initialize(IncrementalGeneratorInitializationContext context)
{
#if DEBUG
    if (!Debugger.IsAttached)
    {
        Debugger.Launch();
    }
#endif

    // 改用RegisterPostInitializationOutput输出代码
    context.RegisterPostInitializationOutput(ctx =>
    {
        ctx.AddSource("JSON.g.cs", SourceText.From(TestSource, Encoding.UTF8));
    });

    // 保留原语法分析逻辑(若需动态生成可后续扩展)
    var todoInput = context.SyntaxProvider
        .CreateSyntaxProvider(
            predicate: static (s, _) => s is ClassDeclarationSyntax,
            transform: static (ctx, _) => ctx.Node)
        .Where(static m => m is not null);
}

注意:如果生成逻辑需要依赖语法分析结果(如根据项目类动态添加JsonSerializable),该方案不适用,需采用方案2。

方案2:指定生成器依赖关系

通过[GeneratorDependency]特性明确生成器执行顺序,强制Json生成器在自定义生成器完成输出后再执行。

在自定义生成器类上添加特性:

[Generator]
[GeneratorDependency(typeof(System.Text.Json.SourceGeneration.JsonSourceGenerator))]
public class CustomGenerator : IIncrementalGenerator
{
    // 原有代码...
}

该特性告知Roslyn,JsonSourceGenerator必须等待CustomGenerator输出代码后再运行,确保Json生成器能在同一轮构建中看到WeatherJsonContext并生成实现代码。

额外注意事项

  • 移除.csproj中<Compile Remove="$(CompilerGeneratedFilesOutputPath)/System.Text.Json.SourceGeneration/**/*.cs" />配置,避免误排除Json生成器的输出代码,导致编译失败。
  • 确保项目引用.NET 6及以上版本的System.Text.Json包,因为Json源代码生成器是.NET 6引入的特性。

内容的提问来源于stack exchange,提问作者Viletung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:30:55