Skip to content

任务索引:我想要...

按照你想要完成的任务查找常见 Source Generator 任务的解决方案

此索引帮助你快速找到适合你任务的 API。每个条目都包含可用的代码示例和详细文档的链接。


🔍 查找和分析

查找项目中的所有类

推荐: 使用 Compilation.GetSymbolsWithName()

csharp
var allClasses = compilation
    .GetSymbolsWithName(name => true, SymbolFilter.Type)
    .OfType<INamedTypeSymbol>()
    .Where(t => t.TypeKind == TypeKind.Class);

foreach (var classSymbol in allClasses)
{
    var className = classSymbol.Name;
    var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
    // 处理类...
}

详细文档 →


查找带有特定特性的类

最佳方法: 使用 ForAttributeWithMetadataName()

csharp
var classesWithAttribute = context.SyntaxProvider
    .ForAttributeWithMetadataName(
        "MyNamespace.MyAttribute",
        predicate: (node, _) => node is ClassDeclarationSyntax,
        transform: (ctx, _) => GetClassInfo(ctx));

static ClassInfo GetClassInfo(GeneratorAttributeSyntaxContext context)
{
    var classDecl = (ClassDeclarationSyntax)context.TargetNode;
    var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
    return new ClassInfo(classSymbol.Name, classSymbol.ContainingNamespace.ToDisplayString());
}

替代方法: 手动过滤(较慢)

csharp
var classesWithAttribute = context.SyntaxProvider
    .CreateSyntaxProvider(
        predicate: (node, _) => node is ClassDeclarationSyntax cls && 
                                cls.AttributeLists.Count > 0,
        transform: (ctx, _) => GetClassWithAttribute(ctx))
    .Where(c => c is not null);

详细文档 →


查找类的所有属性

csharp
var properties = classSymbol.GetMembers()
    .OfType<IPropertySymbol>()
    .Where(p => p.DeclaredAccessibility == Accessibility.Public);

foreach (var property in properties)
{
    var propName = property.Name;
    var propType = property.Type.ToDisplayString();
    var isReadOnly = property.SetMethod == null;
    // 处理属性...
}

详细文档 →


查找类中的所有方法

csharp
var methods = classSymbol.GetMembers()
    .OfType<IMethodSymbol>()
    .Where(m => m.MethodKind == MethodKind.Ordinary); // 排除构造函数等

foreach (var method in methods)
{
    var methodName = method.Name;
    var returnType = method.ReturnType.ToDisplayString();
    var parameters = method.Parameters;
    // 处理方法...
}

详细文档 →


获取类上的所有特性

csharp
var attributes = classSymbol.GetAttributes();

foreach (var attribute in attributes)
{
    var attributeName = attribute.AttributeClass?.Name;
    
    // 获取构造函数参数
    foreach (var arg in attribute.ConstructorArguments)
    {
        var value = arg.Value;
    }
    
    // 获取命名参数
    foreach (var namedArg in attribute.NamedArguments)
    {
        var name = namedArg.Key;
        var value = namedArg.Value.Value;
    }
}

详细文档 →


检查类型是否实现接口

csharp
bool ImplementsInterface(INamedTypeSymbol typeSymbol, string interfaceName)
{
    return typeSymbol.AllInterfaces.Any(i => 
        i.ToDisplayString() == interfaceName);
}

// 使用
if (ImplementsInterface(classSymbol, "System.IDisposable"))
{
    // 类实现了 IDisposable
}

详细文档 →


检查类型是否继承自基类

csharp
bool InheritsFrom(INamedTypeSymbol typeSymbol, string baseClassName)
{
    var current = typeSymbol.BaseType;
    while (current != null)
    {
        if (current.ToDisplayString() == baseClassName)
            return true;
        current = current.BaseType;
    }
    return false;
}

详细文档 →


获取类型的命名空间

csharp
var namespaceName = typeSymbol.ContainingNamespace.ToDisplayString();

// 检查是否在全局命名空间中
if (typeSymbol.ContainingNamespace.IsGlobalNamespace)
{
    // 类型在全局命名空间中
}

详细文档 →


🔨 生成代码

生成简单的类

推荐: 对于简单代码使用基于字符串的生成 ⭐

csharp
var code = $"""
namespace {namespaceName}
{
    public partial class {className}
    {
        public string GeneratedProperty { get; set; }
        
        public void GeneratedMethod()
        {
            // 生成的代码
        }
    }
}
""";

context.AddSource($"{className}.g.cs", code);

详细文档 →


生成带属性的类

csharp
var properties = new[] { ("Name", "string"), ("Age", "int"), ("Email", "string") };

var propertiesCode = string.Join("\n    ", properties.Select(p => 
    $"public {p.Item2} {p.Item1} {{ get; set; }}"));

var code = $"""
namespace {namespaceName}
{
    public partial class {className}
    {
        {propertiesCode}
    }
}
""";

context.AddSource($"{className}.g.cs", code);

详细文档 →


生成方法

csharp
var methodCode = $"""
public {returnType} {methodName}({parameters})
{
    {methodBody}
}
""";

详细文档 →


生成 using 语句

csharp
var usings = new[] { "System", "System.Collections.Generic", "System.Linq" };
var usingStatements = string.Join("\n", usings.Select(u => $"using {u};"));

var code = $"""
{usingStatements}

namespace {namespaceName}
{
    public partial class {className}
    {
        // 类内容
    }
}
""";

详细文档 →


在类上生成特性

csharp
var code = $"""
namespace {namespaceName}
{
    [System.CodeDom.Compiler.GeneratedCode("MyGenerator", "1.0")]
    [System.Diagnostics.DebuggerNonUserCode]
    public partial class {className}
    {
        // 类内容
    }
}
""";

详细文档 →


生成 XML 文档注释

csharp
var code = $"""
namespace {namespaceName}
{
    /// <summary>
    /// 为 {originalClassName} 生成的类
    /// </summary>
    /// <remarks>
    /// 此类是自动生成的。请勿修改。
    /// </remarks>
    public partial class {className}
    {
        /// <summary>
        /// 获取或设置名称
        /// </summary>
        public string Name { get; set; }
    }
}
""";

详细文档 →


使用 SyntaxFactory 生成代码(复杂结构)

何时使用: 对于难以用字符串管理的复杂代码结构

csharp
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

var classDeclaration = ClassDeclaration(className)
    .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.PartialKeyword))
    .AddMembers(
        PropertyDeclaration(
            PredefinedType(Token(SyntaxKind.StringKeyword)),
            "Name")
        .AddModifiers(Token(SyntaxKind.PublicKeyword))
        .AddAccessorListAccessors(
            AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
            AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));

var namespaceDecl = NamespaceDeclaration(ParseName(namespaceName))
    .AddMembers(classDeclaration);

var code = namespaceDecl.NormalizeWhitespace().ToFullString();
context.AddSource($"{className}.g.cs", code);

详细文档 →


生成多个文件

csharp
foreach (var classInfo in classesToGenerate)
{
    var code = GenerateCodeForClass(classInfo);
    context.AddSource($"{classInfo.Name}.g.cs", code);
}

详细文档 →


格式化生成的代码

csharp
// 使用原始字符串字面量并正确缩进
var code = $"""
    namespace {namespaceName}
    {
        public partial class {className}
        {
            public void Method()
            {
                // 正确缩进
            }
        }
    }
    """;

// 或使用 SyntaxFactory 配合 NormalizeWhitespace()
var formatted = syntaxNode.NormalizeWhitespace().ToFullString();

详细文档 →


⚠️ 报告问题

报告错误

csharp
private static readonly DiagnosticDescriptor ErrorRule = new(
    id: "GEN001",
    title: "无效配置",
    messageFormat: "类 '{0}' 的配置无效:{1}",
    category: "Generator",
    DiagnosticSeverity.Error,
    isEnabledByDefault: true);

// 报告错误
var diagnostic = Diagnostic.Create(
    ErrorRule,
    location,
    className,
    errorMessage);

context.ReportDiagnostic(diagnostic);

详细文档 →


报告警告

csharp
private static readonly DiagnosticDescriptor WarningRule = new(
    id: "GEN002",
    title: "潜在问题",
    messageFormat: "类 '{0}' 可能存在问题:{1}",
    category: "Generator",
    DiagnosticSeverity.Warning,
    isEnabledByDefault: true);

context.ReportDiagnostic(Diagnostic.Create(WarningRule, location, className, warning));

详细文档 →


报告信息消息

csharp
private static readonly DiagnosticDescriptor InfoRule = new(
    id: "GEN003",
    title: "信息",
    messageFormat: "为 '{0}' 生成了代码",
    category: "Generator",
    DiagnosticSeverity.Info,
    isEnabledByDefault: true);

context.ReportDiagnostic(Diagnostic.Create(InfoRule, Location.None, className));

详细文档 →


报告带有多个位置的诊断

csharp
var diagnostic = Diagnostic.Create(
    descriptor,
    primaryLocation,
    additionalLocations: new[] { location1, location2 },
    messageArgs: new[] { "arg1", "arg2" });

context.ReportDiagnostic(diagnostic);

详细文档 →


创建自定义诊断严重性

csharp
// Error - 停止编译
DiagnosticSeverity.Error

// Warning - 显示警告但继续编译
DiagnosticSeverity.Warning

// Info - 仅供参考
DiagnosticSeverity.Info

// Hidden - 不显示给用户
DiagnosticSeverity.Hidden

详细文档 →


🚀 性能优化

使用增量生成器

新项目始终使用

csharp
[Generator]
public class MyIncrementalGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        // 带缓存的增量管道
        var classDeclarations = context.SyntaxProvider
            .CreateSyntaxProvider(
                predicate: (node, _) => node is ClassDeclarationSyntax,
                transform: (ctx, _) => (ClassDeclarationSyntax)ctx.Node);
        
        context.RegisterSourceOutput(classDeclarations,
            (spc, classDecl) => GenerateCode(spc, classDecl));
    }
}

详细文档 →


缓存昂贵的计算

csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
    // 步骤 1:查找类(已缓存)
    var classes = context.SyntaxProvider
        .CreateSyntaxProvider(/* ... */);
    
    // 步骤 2:提取信息(每个类缓存)
    var classInfos = classes.Select((cls, _) => ExtractInfo(cls));
    
    // 步骤 3:与编译组合(仅在需要时)
    var combined = context.CompilationProvider.Combine(classInfos.Collect());
    
    // 步骤 4:生成(仅在输入更改时)
    context.RegisterSourceOutput(combined, (spc, source) => Generate(spc, source));
}

详细文档 →


在管道早期过滤

推荐: 尽早过滤 ⭐

csharp
// 好:在 predicate 中过滤(快速)
var classes = context.SyntaxProvider
    .CreateSyntaxProvider(
        predicate: (node, _) => node is ClassDeclarationSyntax cls &&
                                cls.Modifiers.Any(SyntaxKind.PartialKeyword),
        transform: (ctx, _) => ctx.Node);

// 差:在 transform 后过滤(慢)
var classes = context.SyntaxProvider
    .CreateSyntaxProvider(
        predicate: (node, _) => node is ClassDeclarationSyntax,
        transform: (ctx, _) => ctx.Node)
    .Where(cls => ((ClassDeclarationSyntax)cls).Modifiers.Any(SyntaxKind.PartialKeyword));

详细文档 →


避免不必要的语义分析

csharp
// 好:尽可能使用仅语法过滤
var classes = context.SyntaxProvider
    .CreateSyntaxProvider(
        predicate: (node, _) => node is ClassDeclarationSyntax cls &&
                                cls.AttributeLists.Count > 0, // 语法检查
        transform: (ctx, _) => GetSemanticInfo(ctx)); // 仅在需要时使用语义

// 差:总是使用语义模型
var classes = context.SyntaxProvider
    .CreateSyntaxProvider(
        predicate: (node, _) => true, // 无过滤
        transform: (ctx, _) => GetSemanticInfo(ctx)); // 对所有节点都昂贵

详细文档 →


🔧 使用编译

访问编译

csharp
public void Execute(GeneratorExecutionContext context)
{
    var compilation = context.Compilation;
    
    // 使用编译获取语义信息
    var syntaxTree = compilation.SyntaxTrees.First();
    var semanticModel = compilation.GetSemanticModel(syntaxTree);
}

详细文档 →


添加元数据引用

csharp
var references = new[]
{
    MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
    MetadataReference.CreateFromFile(typeof(Console).Assembly.Location)
};

var compilation = CSharpCompilation.Create(
    "MyAssembly",
    syntaxTrees: new[] { syntaxTree },
    references: references);

详细文档 →


获取所有语法树

csharp
foreach (var syntaxTree in compilation.SyntaxTrees)
{
    var root = syntaxTree.GetRoot();
    var filePath = syntaxTree.FilePath;
    // 处理语法树...
}

详细文档 →


📚 其他资源

按类别

按难度

最佳实践


💡 找不到你需要的内容?

  1. 查看快速入门指南了解基本示例
  2. 浏览常见场景了解实际模式
  3. 搜索完整 API 参考了解详细信息
  4. 查看最佳实践了解推荐方法

基于 MIT 许可发布