.net 在解决方案和引用程序集中查找派生接口的符号

z9smfwbn  于 2023-06-25  发布在  .NET
关注(0)|答案(1)|浏览(100)

我正在做的事情(使用Roslyn/Microsoft. CodeAnalysis)

我试图在解决方案和引用的程序集中找到从特定接口继承的接口的所有符号。我的目标是尽可能高效和干净地做到这一点。
在这样做的时候,我手头有以下几件事:

  • roslyn的Solution
  • 接口的符号,我想从中查找派生接口。

方法

不工作

  • 起初我尝试使用SymbolFinder,但以下方法不起作用:
  • SymbolFinder.FindImplementationsAsync(interfaceSymbol, solution) =>这种方法不起作用,因为它只返回类,但没有接口。
  • SymbolFinder.FindDerivedClassesAsync(interfaceSymbol, solution) =>这也只是返回类(方法名已经声明)
  • SymbolFinder.FindReferencesAsync(interfaceSymbol, solution) =>这只是返回当前解决方案中的引用,而不是在被引用的程序集中**。

正在工作

  • 由于上面提到的尝试没有带来有用的结果,我的最后一招是手动蛮力方法,我基本上收集所有IAssemblySymbols,迭代所有类型并检查接口(递归完成,使用SymbolVisitor)。

那么,我为什么要寻找另一个解决方案呢?

  • 我希望内置的解决方案在性能方面会更好,因为可能已经缓存了一些东西,或者它也可能使用其他数据结构等,因为SymbolFinder中的场景就是这样
  • 除此之外:不那么复杂更稳定

我的问题

  • 有没有更简单、更快的解决方案(类似于SymbolFinder已经提供的)?
thtygnil

thtygnil1#

由于到目前为止还没有提出任何改进建议,以下是我最初的工作方法-只是为了完整起见:

private static ConcurrentBag<INamedTypeSymbol> GetImplementingSymbols(Project project)
{
    var compilation = project.GetCompilationAsync().Result;
    var typeToLookFor = compilation.GetTypeByMetadataName(typeof(IAnyInterface).FullName);

    var assemblySymbols =
        project.MetadataReferences
            .Select(compilation.GetAssemblyOrModuleSymbol)
            .OfType<IAssemblySymbol>()
            .ToList();

    assemblySymbols.Add(compilation.Assembly);

    var foundSymbols = new ConcurrentBag<INamedTypeSymbol>();

    Parallel.ForEach(assemblySymbols, symbol =>
    {
        var getAllSymbolsVisitor = new GetAllSymbolsVisitor(typeToLookFor, foundSymbols);
        getAllSymbolsVisitor.Visit(symbol.GlobalNamespace);
    });

    return foundSymbols;
}

private class GetAllSymbolsVisitor : SymbolVisitor
{
    private readonly ConcurrentBag<INamedTypeSymbol> _symbols;
    private INamedTypeSymbol _type;

    public GetAllSymbolsVisitor(INamedTypeSymbol type, ConcurrentBag<INamedTypeSymbol> symbols)
    {
        _symbols = symbols;
        _type = type;
    }

    public override void VisitNamespace(INamespaceSymbol symbol)
    {
        foreach (var namespaceOrTypeSymbol in symbol.GetMembers())
        {
            namespaceOrTypeSymbol.Accept(this);
        }
    }

    public override void VisitNamedType(INamedTypeSymbol symbol)
    {
        if (symbol.Interfaces.Any(interfaceType => SymbolEqualityComparer.Default.Equals(_type, interfaceType)))
        {
            _symbols.Add(symbol);
        }
    }
}

相关问题