2016-07-21 94 views
0

Ich versuche ein Plugin für Visual Studio 2015 zu entwickeln. Ich habe Befehl, der zum Kontextmenü hinzugefügt wird, wenn ein Projekt mit der rechten Maustaste angeklickt wird und ich das Projekt, das richtig geklickt wurde, abrufen kann. Jetzt versuche ich festzustellen, ob das Projekt eine Klasse enthält, die eine bestimmte Schnittstelle implementiert. Also ist mein erster Schritt, die Klassen in das Projekt zu bekommen. Also habe ich so etwas wie dieses:Ermitteln, ob CodeElement zum Projekt gehört

protected IEnumerable<EnvDTE.CodeClass> GetClasses(EnvDTE.CodeElements elements, 
                EnvDTE.Project project) 
{ 
    foreach (EnvDTE.CodeElement element in elements) 
    { 
     System.Diagnostics.Debug.WriteLine(element.InfoLocation); 

     var cls = element as EnvDTE.CodeClass; 
     if (cls != null) 
     { 
      yield return cls; 
     } 
     var ns = element as EnvDTE.CodeNamespace; 
     if (ns != null) 
     { 
      foreach (var childCls in GetClasses(ns.Members, project)) 
      { 
       yield return childCls; 
      } 
     } 
    } 
} 

So wird dies durchlaufen und Klassen herausziehen. Das Problem besteht darin, dass alles, was referenziert wird, BCL-Klassen umfasst. Ich dachte, mit InfoLocation könnte helfen, aber alles zurück vsCMInfoLocationExternal (vermutlich, weil in dem Kontext, in dem das Plugin ausgeführt wird, sind sie extern). Ich habe versucht, Dinge wie element.ProjectItem und element.ProjectItem.ContainingProject und element.Parent mit der Hoffnung, das mit dem übergeordneten Projekt zu vergleichen, aber diese alle werfen System.Runtime.InteropServices.COMException. Also gibt es einen Weg, da ich das Projekt kenne, um festzustellen, ob ein bestimmter CodeElement Teil des Projekts ist, oder nur von dem Projekt referenziert?

EDIT: Das Beste, was ich habe in der Lage gewesen, mit so weit zu kommen, dies zu tun, erhalten zunächst das Standard-Namespace für das Projekt:

var defaultNS = project.Properties.Item("DefaultNamespace").Value.ToString(); 

Und dann kann ich dies tun:

if (ns != null && ns.Name == defaultNS) 

So jetzt werde ich nicht gehen hinunter in System, was gut ist. Das einzige Problem wäre, wenn ein Projekt mehrere Namespaces hätte, die ich durchsuchen wollte. Ich kann nicht herausfinden, ob es eine Möglichkeit gibt, eine Liste von Namespaces zu erhalten, die im Projekt definiert sind.

Edit: Die vorgeschlagene dupe befasst sich mit Type so ist nicht ganz relevant.

+2

ich diese Kennzeichnung als dup von http://stackoverflow.com/questions/3174921/how-do-i-determine-if-system-type-is-a-custome-type-or -a-framework-type, weil es wirklich keine Möglichkeit gibt, dies innerhalb oder außerhalb einer vs-Erweiterung zu tun. –

+0

@PaulSwetz: Es kann sein, dass es keine Möglichkeit gibt, es zu tun, aber der vorgeschlagene Betrogene ist nicht das Gleiche und ist hier nicht hilfreich. Ich habe nicht den "Typ", ich habe ein 'CodeElement', daher sind Vorschläge mit' Typ' nicht relevant. –

+0

Ich könnte eine Antwort aufsetzen, die rund um was Sie wollen, indem Sie herausfinden, welche Klasse/enum/Strukturen in einem Codeelement von externen Referenz vs in Lösungsdefinitionen kommen. Es * kann * passen Sie Ihre Bedürfnisse, kann nicht sagen, es sehr effizient, obwohl es sehr rekursiv. –

Antwort

1

Dies kann Ihren Anforderungen entsprechen oder es ist möglicherweise nicht, aber das ist, was ich verwendet, um Code-Elemente zu analysieren und herausfinden, ob die Definition in der Lösung ist oder wenn es über eine Referenz kommt. Es gibt keine Möglichkeit zu wissen, ob die Referenz 3rd Party gegen BCL ist. Einige Codes wurden aus Platzgründen entfernt, da sie sich in einer API befinden und schwer zu durchbrechen sind. Sie könnten einen Trick hinzufügen, sobald Sie die Typen vollständigen Namen und wissen, dass es eine Referenz, wo Sie alle DLLs, die mit dem Microsoft-Schlüssel für den Typnamen signiert sind, wenn Sie eine seiner bcl finden, sonst wahrscheinlich ist nicht.

public static string CodeElementAsTypeFullName(EnvDTE80.CodeElement2 element) 
    { 
     if (element == null) 
      throw new ArgumentNullException(nameof(element)); 
     if (element.Kind == vsCMElement.vsCMElementClass 
      || element.Kind == vsCMElement.vsCMElementEnum 
      || element.Kind == vsCMElement.vsCMElementStruct) 
      return element.FullName; 
     else 
      return ((dynamic)element).Type.AsFullName; 
    } 
protected void FlattenElement(EnvDTE80.CodeElement2 element) 
{       
     try 
     { 
      string varType = CodeElementAsTypeFullName(element);    
      switch (element.Kind) 
      { 
       case vsCMElement.vsCMElementVariable: 
       case vsCMElement.vsCMElementProperty: 
       { 
        EnvDTE80.CodeElement2 defined = null; 
        ///this is API, basically a collection of all the files in the solution with all class/enum/stuct defs parsed out into collections. 
        foreach (SquishFile file in this.solutionFiles) 
        { 
         //next line goes through each solution file one by one to figure out if the file defines the class/enum/struct definition. 
         defined = file.ContainsCodeElement(varType); 
         if (defined != null) 
          break; 
        } 
        if (defined != null) 
        { 
         if (defined.Kind == vsCMElement.vsCMElementClass 
             || defined.Kind == vsCMElement.vsCMElementStruct 
             || defined.Kind == vsCMElement.vsCMElementEnum) 
            //THE ITEM IS DEFINED LOCALLY!  
        }else 
         //the item is a reference 
     } 
     } 
    } 
    public class SquishFile 
{   
    public ConcurrentBag<CodeClass> ClassDefinitions = new ConcurrentBag<CodeClass>(); 
    public ConcurrentBag<CodeEnum> EnumDefinitions = new ConcurrentBag<CodeEnum>(); 
    public ConcurrentBag<CodeStruct> StructDefinitions = new ConcurrentBag<CodeStruct>(); 

    protected ProjectItem _projectItem; 
    public ProjectItem ProjectItem { get { return _projectItem; } } 
    public SquishFile(ProjectItem projectItem) 
    { 
     if (projectItem.FileCodeModel == null) 
      throw new Exception("Cannot make a squish file out of a project item with no FileCodeModel!"); 

     _projectItem = projectItem; 
     foreach (EnvDTE80.CodeElement2 ele in projectItem.FileCodeModel.CodeElements) 
      Discovery(ele); 
    } 

    public EnvDTE80.CodeElement2 ContainsCodeElement(string fullName) 
    { 
     foreach(EnvDTE80.CodeElement2 ele in ClassDefinitions) 
      if (ele.FullName.Equals(fullName)) 
       return ele; 
     foreach (EnvDTE80.CodeElement2 ele in EnumDefinitions) 
      if (ele.FullName.Equals(fullName)) 
       return ele; 
     foreach (EnvDTE80.CodeElement2 ele in StructDefinitions) 
      if (ele.FullName.Equals(fullName)) 
       return ele; 
     return null; 
    } 
    protected void Discovery(EnvDTE80.CodeElement2 element) 
    { 
     if (element.IsCodeType && element.Kind == vsCMElement.vsCMElementClass) 
      this.ClassDefinitions.Add(element as EnvDTE80.CodeClass2); 
     else if (element.IsCodeType && element.Kind == vsCMElement.vsCMElementEnum) 
      this.EnumDefinitions.Add(element as EnvDTE.CodeEnum); 
     else if (element.IsCodeType && element.Kind == vsCMElement.vsCMElementStruct) 
      this.StructDefinitions.Add(element as EnvDTE80.CodeStruct2); 
     foreach (EnvDTE80.CodeElement2 ele in element.Children) 
      Discovery(ele); 
    } 
}