给定INamedTypeSymbol
(来自引用的程序集,而不是源代码)如何找到从此类型继承的所有类型(在源程序集和引用程序集中)?
在我的特定情况下,我正在寻找从NUnit.Framework.TestAttribute
继承的所有类型。我可以按如下方式访问命名类型符号:
var ws = MSBuildWorkspace.Create();
var soln = ws.OpenSolutionAsync(@"C:\Users\...\SampleInheritanceStuff.sln").Result;
var proj = soln.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;
string TEST_ATTRIBUTE_METADATA_NAME = "NUnit.Framework.TestAttribute";
var testAttributeType = compilation.GetTypeByMetadataName(TEST_ATTRIBUTE_METADATA_NAME);
//Now how do I find types that inherit from this type?
我已经看过SymbolFinder
,Compilation
和INamedTypeSymbol
,但我没有运气。
修改:FindDerivedClassesAsync
方法看起来接近我需要的方法。 (我不是100%确定它在引用的程序集中找到派生类)。不过它是内部的,所以我打开了an issue。
答案 0 :(得分:3)
FindDerivedClassesAsync
确实是你要找的
它在引用的程序集中找到派生类,您可以在DependentTypeFinder
的源代码中看到(注意locationsInMetadata
变量)。
至于使用它,你可以随时用反射来做到这一点:
private static readonly Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>> FindDerivedClassesAsync
= new Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>>(() => (Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>)Delegate.CreateDelegate(typeof(Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>), DependentTypeFinder.Value.GetMethod("FindDerivedClassesAsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)));
(code borrowed from Tunnel Vision Laboratories Github)
祝你好运!<强>更新强>
此方法现已公开。 (source)
答案 1 :(得分:0)
您可以使用Compilation
中公开的SemanticModel获取此信息public static IEnumerable<INamedTypeSymbol> GetBaseClasses(SemanticModel model, BaseTypeDeclarationSyntax type)
{
var classSymbol = model.GetDeclaredSymbol(type);
var returnValue = new List<INamedTypeSymbol>();
while (classSymbol.BaseType != null)
{
returnValue.Add(classSymbol.BaseType);
if (classSymbol.Interfaces != null)
returnValue.AddRange(classSymbol.Interfaces);
classSymbol = classSymbol.BaseType;
}
return returnValue;
}
这将为您提供所有基类的列表以及每个基类实现的每个接口。然后,您可以过滤到您感兴趣的INamedTypeSymbol:
public static IEnumerable<BaseTypeDeclarationSyntax>
FindClassesDerivedOrImplementedByType(Compilation compilation
, INamedTypeSymbol target)
{
foreach (var tree in compilation.SyntaxTrees)
{
var semanticModel = compilation.GetSemanticModel(tree);
foreach (var type in tree.GetRoot().DescendantNodes()
.OfType<TypeDeclarationSyntax>())
{
var baseClasses = GetBaseClasses(semanticModel, type);
if (baseClasses != null)
if (baseClasses.Contains(target))
yield return type;
}
}
}