Поскольку предлагаемых улучшений пока нет, вот мой первоначальный рабочий подход - просто для полноты:
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);
}
}
}