在解决方案和引用组件中找到派生接口的符号。

问题描述 投票:0回答:1

我想做的是(使用RoslynMicrosoft.CodeAnalysis)。

我试图找到解决方案中所有从特定接口继承的接口符号,以及被引用的集合。我的目标是尽可能高效、干净地完成这项工作。

在做这件事的时候,我手头有以下东西。

  • roslyn Solution.
  • 符号是接口,我想从中找到派生接口。

方法

不工作

  • 一开始我是想用 SymbolFinder,但下面的方法没有用。
    • SymbolFinder.FindImplementationsAsync(interfaceSymbol, solution) => 这种方法行不通,因为它只返回类,而没有接口。
    • SymbolFinder.FindDerivedClassesAsync(interfaceSymbol, solution) => 这也只是返回类(因为方法名已经说明了)。
    • SymbolFinder.FindReferencesAsync(interfaceSymbol, solution) => 这只是返回当前解决方案中的引用,但 引用的程序集中。

工作

  • 由于上述尝试并没有得到有用的结果,我最后的办法是采用人工蛮力的方法,基本上是收集所有的 IAssemblySymbols迭代所有类型并检查接口(以递归的方式完成,用一个 SymbolVisitor).

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

  • 我期望一个内置的解决方案在性能方面会更好,因为可能已经有一些东西被缓存了,或者它也可能使用其他数据结构等,因为这是在幕后的情况下,在 SymbolFinder
  • 除此之外:更少的复杂,更稳定,......

我的问题

  • 是否有更简单、更快速的解决方案(类似于我们现在所做的 SymbolFinder 已经提供的)?)
.net roslyn roslyn-code-analysis microsoft.codeanalysis
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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.