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

C#增量源代码生成器未运行,请求排查问题

增量源代码生成器未触发、无文件生成问题排查

我想要创建一个增量源代码生成器,用于读取JSON文件并生成对应的类。但构建解决方案时没有生成任何文件,甚至生成器中的调试语句也未触发。

生成器项目配置

<PropertyGroup>
  <TargetFramework>netstandard2.0</TargetFramework>
  <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
  <IsRoslynComponent>true</IsRoslynComponent>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
  <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.5.0" PrivateAssets="all" />
  <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

<ItemGroup>
  <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>

应用项目引用方式

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

生成器代码

[Generator]
public class MetricsSourceGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext initContext)
    {
        System.Diagnostics.Debugger.Launch();

        var textFile = initContext.AdditionalTextsProvider.Where(file => file.Path.Contains("Potato"));

        var contentProvider = textFile.Select((text, cancellationToken) => text.GetText(cancellationToken).ToString());

        initContext.RegisterSourceOutput(contentProvider, (sourceProductionContext, fileContents) =>
        {
            var metricDefinitions = JsonConvert.DeserializeObject<MetricDefinitions>(fileContents);

            foreach (var metric in metricDefinitions.Metrics)
            {
                var source = GenerateClassSourceCode(metric);

                sourceProductionContext.AddSource(metric.Name + "AnalyticsCounter.cs", SourceText.From(source, Encoding.UTF8));
            }
        });
    }

    private string GenerateClassSourceCode(MetricDefinition metric)
    {
        var className = metric.Name + "AnalyticsCounter";

        var dimensionsOwnParameters = string.Join(", ", metric.Dimensions.Select(dimensionName => $"string {dimensionName}"));

        var dimensionsTrackValueParameters = string.Join(", ", metric.Dimensions);

        return $@"
// <auto-generated/>
using System.Collections.Generic;
using Microsoft.ApplicationInsights;

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This class is auto-generated by {this.GetType().Name}.
Please DO NOT modify it manually!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
namespace App.DataLayer.Analytics.Metrics
{{
    public class {className} : AnalyticsCounter
    {{
        public {className}(TelemetryClient telemetryClient)
            : base(""{metric.Name}"", telemetryClient)
        {{
        }}

        public void Increment({dimensionsOwnParameters})
        {{
            Metric.TrackValue(1, {dimensionsTrackValueParameters});
        }}
    }}
}}
";
    }
}

public class MetricDefinitions
{
    public MetricDefinition[] Metrics { get; set; }
}

public class MetricDefinition
{
    public string Name { get; set; }

    public bool IsSimpleCounter { get; set; }

    public string[] Dimensions { get; set; }
}

请问我哪里操作有误?是否需要采用其他构建方式?


问题排查与解决方案

1. JSON文件未标记为AdditionalText

生成器依赖AdditionalTextsProvider获取文件,若目标JSON文件未被识别为AdditionalText,生成器不会触发。需在应用项目中将JSON文件的BuildAction设置为AdditionalFiles:

<ItemGroup>
  <AdditionalFiles Include="**/Potato*.json" />
</ItemGroup>

确保文件路径包含"Potato",匹配代码中的过滤条件file.Path.Contains("Potato")。

2. 生成器项目依赖配置问题

  • 增量生成器无需引用Microsoft.CodeAnalysis.CSharp.Workspaces,替换为轻量化的Microsoft.CodeAnalysis.CSharp包:
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="all" />
    
  • Newtonsoft.Json未设置PrivateAssets="all",可能引发依赖冲突,修改为:
    <PackageReference Include="Newtonsoft.Json" Version="13.0.2" PrivateAssets="all" />
    

3. 调试语句的局限性

System.Diagnostics.Debugger.Launch()在常规编译环境中可能无法触发(生成器运行在编译进程内),改用诊断输出验证生成器是否启动:

initContext.ReportDiagnostic(Diagnostic.Create(
    new DiagnosticDescriptor("GEN001", "Generator Started", "Metrics生成器已初始化", "Generator", DiagnosticSeverity.Info, true),
    Location.None));

可在VS的「错误列表」中查看该诊断信息。

4. 生成代码的语法错误

生成的构造函数代码存在双引号转义错误:base(""{metric.Name}"", telemetryClient)会生成无效的字符串格式,修改为:

base($"{metric.Name}", telemetryClient)

语法错误会导致生成的代码无法编译,VS会自动隐藏错误的生成文件,因此你看不到输出结果。

5. 构建缓存与路径问题

  • 清理解决方案,删除bin、obj文件夹后重新构建,避免旧缓存干扰。
  • CompilerGeneratedFilesOutputPath默认在生成器项目目录下,若需在应用项目中查看生成文件,需在应用项目的PropertyGroup中添加:
    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
    

6. 增量生成器逻辑的健壮性优化

添加空值检查,避免空引用异常导致生成器崩溃:

var contentProvider = textFile.Select((text, cancellationToken) => 
{
    var textContent = text.GetText(cancellationToken);
    return textContent?.ToString() ?? string.Empty;
});

同时在反序列化后检查metricDefinitions和metricDefinitions.Metrics是否为空:

if (metricDefinitions?.Metrics == null) return;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:38:15