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

如何在ISyntaxContextReceiver中对比生成类型,检测类标记的指定特性

解决方案

核心思路

不要手动对比零散的名称字符串,用Roslyn提供的SymbolEqualityComparer做类型符号全等对比,可覆盖别名、嵌套、同名不同命名空间等所有场景,不会出现误判。

具体实现步骤

步骤1:在生成器Execute阶段预获取目标特性的类型符号

在你第二个需要检测特性的生成器的Execute方法中,先从编译上下文拿到你生成的目标特性的ITypeSymbol:

public void Execute(GeneratorExecutionContext context)
{
    // 注意元数据名称要写全,带Attribute后缀、完整命名空间
    var targetAttributeType = context.Compilation.GetTypeByMetadataName("DependencyReproGenerator.Library.Attributes.CustomAttribute1Attribute");
    if (targetAttributeType == null)
    {
        // 未找到目标特性,说明当前项目没有引用生成特性的生成器,直接返回
        return;
    }

    // 拿到Receiver里收集的类声明
    if (context.SyntaxContextReceiver is not ConstructorGeneratorReceiver receiver) return;

    // 后续处理逻辑
}

步骤2:优化SyntaxReceiver的判断逻辑

不需要手动解析Attribute的语法Token,直接拿到类的类型符号后遍历其特性列表,用符号比较器判断:

class ConstructorGeneratorReceiver : ISyntaxContextReceiver
{
    public List<INamedTypeSymbol> MarkedClasses { get; } = new();

    public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
    {
        if (context.Node is not ClassDeclarationSyntax classDec) return;

        // 拿到当前类的类型符号
        if (context.SemanticModel.GetDeclaredSymbol(classDec) is not INamedTypeSymbol classSymbol) return;

        // 遍历类的所有特性
        foreach (var attributeData in classSymbol.GetAttributes())
        {
            // 特性类型为空直接跳过
            if (attributeData.AttributeClass == null) continue;

            // 这里先临时用完整名称对比,等Execute阶段拿到目标类型后也可以用SymbolEqualityComparer.Default.Equals做二次过滤,准确性更高
            if (attributeData.AttributeClass.ToDisplayString() == "DependencyReproGenerator.Library.Attributes.CustomAttribute1Attribute")
            {
                MarkedClasses.Add(classSymbol);
                break;
            }
        }
    }
}

可选:直接在Receiver中做精确对比的简化写法

如果你不想在Execute阶段二次过滤,也可以直接在遍历Attribute时拿到特性类型符号后对比名称+命名空间:

private bool IsTargetAttribute(ITypeSymbol? attributeType)
{
    if (attributeType == null) return false;
    return attributeType.Name == "CustomAttribute1Attribute" 
           && attributeType.ContainingNamespace.ToDisplayString() == "DependencyReproGenerator.Library.Attributes";
}

注意事项

  • 不要省略特性的Attribute后缀,元数据中存储的类型名是完整带后缀的,用GetTypeByMetadataName时必须写全
  • SymbolEqualityComparer.Default.Equals是官方提供的类型符号全等判断方法,比手动拼接字符串更可靠,可处理类型重定向、别名引用等特殊场景
  • 同一个解决方案中多个源生成器的输出会被合并到编译上下文,只要生成特性的生成器被项目正确引用,就能通过GetTypeByMetadataName拿到对应的类型符号

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:24:00