0

我正在尝试做什么(与 Roslyn/Microsoft.CodeAnalysis 合作)

我试图在解决方案以及引用的程序集中查找从特定接口继承的所有接口符号。我的目标是尽可能高效和干净地做到这一点。

在这样做的时候,我手头有以下东西:

  • 罗斯林Solution
  • 如果接口的符号,我想从中找到派生接口。

方法

不工作

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

在职的

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

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

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

我的问题

  • 是否有任何更简单且可能更快的解决方案(类似于SymbolFinder已经提供的解决方案)?
4

1 回答 1

0

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

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);
        }
    }
}
于 2020-05-03T14:13:11.260 回答