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

增量源代码生成器如何获取符号(含依赖)的所有实现?

在增量源代码生成器中查找接口的所有实现(含依赖程序集)

核心思路

源代码生成器环境下无法直接使用独立Roslyn环境的SymbolFinder方法,但可以通过Compilation对象结合符号遍历、匹配逻辑实现需求,且天然支持访问依赖程序集中的符号。

具体实现步骤

1. 获取编译上下文

在生成器初始化阶段,通过CompilationProvider拿到当前编译的入口对象Compilation,它包含了当前项目及所有依赖程序集的符号信息:

context.RegisterSourceOutput(context.CompilationProvider, (spc, compilation) =>
{
    // 后续逻辑基于此compilation对象展开
});

2. 遍历并匹配接口实现

通过全局命名空间递归遍历所有可见类型,检查类型是否实现了目标接口(含间接实现):

// 先获取目标接口的符号
var targetInterface = compilation.GetTypeByMetadataName("Your.Namespace.IYourInterface");
if (targetInterface == null) return;

var implementations = new List<INamedTypeSymbol>();
TraverseNamespace(compilation.GlobalNamespace, targetInterface, implementations);

// 递归遍历命名空间的方法
void TraverseNamespace(INamespaceSymbol ns, INamedTypeSymbol targetInterface, List<INamedTypeSymbol> result)
{
    foreach (var member in ns.GetMembers())
    {
        if (member is INamespaceSymbol nestedNs)
        {
            TraverseNamespace(nestedNs, targetInterface, result);
        }
        else if (member is INamedTypeSymbol type)
        {
            // 用SymbolEqualityComparer确保符号匹配的准确性
            if (type.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, targetInterface)))
            {
                result.Add(type);
            }
        }
    }
}

3. 增量优化(适配Incremental Source Generator)

如果需要提升性能,避免每次全量遍历,可结合SyntaxProvider筛选可能的候选类型,再做符号验证:

var interfaceImplementations = context.SyntaxProvider
    .CreateSyntaxProvider(
        // 先筛选语法节点:只处理类型声明
        predicate: (node, _) => node is TypeDeclarationSyntax,
        // 转换为符号并验证是否实现目标接口
        transform: (ctx, _) =>
        {
            var typeSymbol = ctx.SemanticModel.GetDeclaredSymbol(ctx.Node) as INamedTypeSymbol;
            var targetInterface = ctx.SemanticModel.Compilation.GetTypeByMetadataName("Your.Namespace.IYourInterface");
            return typeSymbol != null && typeSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, targetInterface)) 
                ? typeSymbol 
                : null;
        })
    .Where(type => type != null);

// 注册输出逻辑
context.RegisterSourceOutput(interfaceImplementations, (spc, type) =>
{
    // 生成对应代码
});

关键注意事项

  • 必须使用SymbolEqualityComparer.Default比较符号,不能直接用==,否则会因符号实例不同导致匹配失败。
  • 处理泛型接口时,需额外检查ConstructedFrom属性是否等于目标接口的原始定义。
  • 若目标接口在当前项目定义,也可先通过SyntaxProvider定位到接口符号,再进行后续匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 09:35:11