我试图找到解决方案中所有从特定接口继承的接口符号,以及被引用的集合。我的目标是尽可能高效、干净地完成这项工作。
在做这件事的时候,我手头有以下东西。
Solution
.SymbolFinder
,但下面的方法没有用。SymbolFinder.FindImplementationsAsync(interfaceSymbol, solution)
=> 这种方法行不通,因为它只返回类,而没有接口。SymbolFinder.FindDerivedClassesAsync(interfaceSymbol, solution)
=> 这也只是返回类(因为方法名已经说明了)。SymbolFinder.FindReferencesAsync(interfaceSymbol, solution)
=> 这只是返回当前解决方案中的引用,但 不 引用的程序集中。IAssemblySymbols
迭代所有类型并检查接口(以递归的方式完成,用一个 SymbolVisitor
).SymbolFinder
SymbolFinder
已经提供的)?)由于到目前为止还没有任何改进建议,这里是我最初的工作方法--只是为了完整。
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);
}
}
}