每个 class 获取一个 Roslyn 语法接收器

Getting one Roslyn syntax receiver per class

我有一个简单的源代码生成器定义为

[Generator]
public class NestedObjectGenerator : ISourceGenerator
{
  public void Initialize(GeneratorInitializationContext context)
  {
    context.RegisterForSyntaxNotifications(() => new MySyntaxReceiver());
  }
  public void Execute(GeneratorExecutionContext context)
  {
    var recv = (MySyntaxReceiver)context.SyntaxReceiver;
    ClassDeclarationSyntax cds = recv?.Class;
    if (cds is null) return;

    // use cds here
  }

  private class MySyntaxReceiver : ISyntaxReceiver
  {
    public ClassDeclarationSyntax Class { get; private set; }

    public void OnVisitSyntaxNode(SyntaxNode node)
    {
      if (node is ClassDeclarationSyntax cds &&
        cds.Modifiers.Any(SyntaxKind.PartialKeyword))
      Class = cds;
    }
  }
}

我正在 运行 将此生成器连接到一个文件中,该文件中有多个部分 classes。但是,似乎 Execute() 只被调用一次,并且包含的​​ Class 是具有 Main() 方法的 class,即使我有其他 class在文件中。

所以,我的问题是:如何在每个受影响的语法节点中将 Execute() 变为 运行 一次,即,对于每个部分 class 将其变为 运行 一次?

您可以这样更改您的接收器:

private class MySyntaxReceiver : ISyntaxReceiver
{
  public List<ClassDeclarationSyntax> ClassCandidates { get; } = new();

  public void OnVisitSyntaxNode(SyntaxNode node)
  {
    if (node is ClassDeclarationSyntax cds && cds.Modifiers.Any(SyntaxKind.PartialKeyword))
      ClassCandidates.Add(cds);
  }
}

然后在源代码生成器的 Execute 方法中,您可以在您收集的所有节点上循环。 我从一个非常有用的视频中得到了这种方法

https://www.youtube.com/watch?v=P9Pv5IdinMU

这里是 github 演示文稿中的演示,我从这些示例中学到了这一点:

https://github.com/JasonBock/SourceGeneratorDemos