2015-08-28 6 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? 

मैं SymbolFinder, Compilation और INamedTypeSymbol पर एक नज़र लिया है, लेकिन मैं किसी भी भाग्य नहीं किया है।

संपादित करें:FindDerivedClassesAsync विधि मेरी आवश्यकता के करीब दिखती है। (मुझे 100% यकीन नहीं है कि यह संदर्भित असेंबली में व्युत्पन्न कक्षाएं पाता है)। हालांकि यह आंतरिक है, इसलिए मैंने an issue खोला है।

+0

क्या आपके पास "असेंबली" ऑब्जेक्ट का संदर्भ हो सकता है? –

+1

यदि आपके पास असेंबली ऑब्जेक्ट हो सकता है तो आप GetTypies विधि का उपयोग कर सकते हैं और विधि IsAssignable से उपयोग कर फ़िल्टर कर सकते हैं –

+0

'विधानसभा' ऑब्जेक्ट प्राप्त करना आसान नहीं होगा, और मुझे पता है कि प्रतिबिंब के साथ करना संभव है, लेकिन मैं वास्तव में पसंद करूंगा 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)

गुड लक!

अद्यतन:

इस विधि अब तक सार्वजनिक किया गया है। (source)

+0

मैंने आपको बक्षीस दिया है (लेकिन जवाब नहीं) क्योंकि यह अब तक का सबसे नज़दीकी दृष्टिकोण है। दुर्भाग्यवश ऐसा नहीं लगता है कि इस एपीआई संदर्भित असेंबली में व्युत्पन्न प्रकार पाता है। – JoshVarty

+1

मैंने आज इसका परीक्षण किया और ऐसा लगता है कि संदर्भित असेंबली में व्युत्पन्न प्रकार भी मिलते हैं। – JoshVarty

0

आप इस जानकारी 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; 
    } 

यह आपको हर इंटरफ़ेस है कि प्रत्येक आधार वर्ग औजार सभी आधार वर्ग की एक सूची के साथ ही दे देंगे से अवगत कराया का उपयोग कर प्राप्त कर सकते हैं। इसके बाद आप INAMETypeSymbol पर फ़िल्टर कर सकते हैं जिसमें आप रुचि रखते हैं:

 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; 
      } 
     } 
    } 
संबंधित मुद्दे