2015-08-28 13 views
9

Cho một số INamedTypeSymbol (xuất phát từ một hội đồng tham chiếu chứ không phải nguồn) làm cách nào tôi có thể tìm thấy tất cả các loại (trong cả hai nguồn nguồn và tham chiếu cụm).Tìm các loại được kế thừa từ INamedTypeSymbol

Trong trường hợp cụ thể của tôi, tôi đang tìm tất cả các loại được kế thừa từ NUnit.Framework.TestAttribute. Tôi có thể được tiếp cận với các biểu tượng kiểu đặt tên như sau:

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? 

Tôi đã lấy một cái nhìn tại SymbolFinder, CompilationINamedTypeSymbol nhưng tôi đã không có bất kỳ may mắn.

Chỉnh sửa: Phương thức FindDerivedClassesAsync trông gần với những gì tôi cần. (Tôi không chắc chắn 100% rằng nó tìm thấy các lớp dẫn xuất trong các assembly được tham chiếu). Tuy nhiên nó là nội bộ, vì vậy tôi đã mở an issue.

+0

Bạn có thể tham chiếu đến đối tượng "Lắp ráp" không? –

+1

Nếu bạn có thể có đối tượng assembly, bạn có thể sử dụng phương thức GetTypies và lọc bằng phương thức IsAssignableFrom –

+0

Nó sẽ không dễ dàng để có được đối tượng 'Assembly', và tôi biết nó có thể làm với sự phản chiếu, nhưng tôi thực sự thích để sử dụng Roslyn. – JoshVarty

Trả lời

3

FindDerivedClassesAsync thực sự là những gì bạn đang tìm kiếm.
Nó tìm thấy các lớp dẫn xuất trong các hội đồng được tham chiếu, như bạn có thể thấy trong mã nguồn cho DependentTypeFinder (thông báo biến số locationsInMetadata).

Đối với sử dụng nó, bạn luôn có thể làm điều đó với suy nghĩ trong khi chờ đợi:

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)

Chúc may mắn!

UPDATE:

Phương pháp này đã được công bố bởi bây giờ. (source)

+0

Tôi đã trao cho bạn tiền thưởng (nhưng không phải là câu trả lời) vì đây là cách tiếp cận gần nhất mà tôi đã nhìn thấy. Thật không may nó không giống như API này tìm thấy các loại có nguồn gốc trong hội đồng tham chiếu. – JoshVarty

+1

Tôi đã thử nghiệm này ngày hôm nay và có vẻ như để tìm các loại có nguồn gốc trong hội đồng tham chiếu là tốt. – JoshVarty

0

Bạn có thể nhận được thông tin này bằng cách sử dụng SemanticModel tiếp xúc từ Compilation

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

này sẽ cung cấp cho bạn một danh sách tất cả các lớp cơ sở cũng như tất cả các giao diện mà mỗi lớp cơ sở thực hiện. Sau đó, bạn có thể lọc thành INamedTypeSymbol mà bạn quan tâm:

 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; 
      } 
     } 
    } 
Các vấn đề liên quan