2015-08-28 27 views
9

給定INamedTypeSymbol(來自引用的程序集,而不是源)如何找到從此類型繼承的所有類型(在源和引用的程序集中)?查找從給定的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? 

我已經採取一看SymbolFinderCompilationINamedTypeSymbol,但我沒有任何運氣。

編輯:FindDerivedClassesAsync方法看起來接近我所需要的。 (我不是100%確定它在引用程序集中找到派生類)。不過它是內部的,所以我打開了an issue

+0

您可以參考「Assembly」對象嗎? –

+1

如果你可以擁有程序集對象,那麼你可以使用方法GetTypies並使用方法IsAssignableFrom來過濾 –

+0

獲取'Assembly'對象並不容易,而且我知道可以使用反射,但是我更喜歡使用Roslyn。 – JoshVarty

回答

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

祝你好運!

UPDATE:

這種方法已經被公開到現在。 (source)

+0

我給你賞金(但不是答案),因爲這是我見過的最接近的方法。不幸的是,它看起來並不像這個API在引用程序集中找到派生類型。 – JoshVarty

+1

我今天測試了它,它似乎也在引用程序集中找到派生類型。 – JoshVarty

0

你可以使用從編

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; 
    } 

這會給你所有的基類的列表,以及每一個接口,每基類實現暴露SemanticModel此信息。然後,您可以過濾到您感興趣的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; 
      } 
     } 
    }