2016-07-21 21 views
0

私はVisual Studio 2015のプラグインを開発しようとしています。プロジェクトを右クリックして右クリックしたときにコンテキストメニューに追加されるコマンドがあります。今私がしようとしているのは、プロジェクトに特定のインタフェースを実装するクラスが含まれているかどうかを判断することです。だから私の最初のステップは、プロジェクトのクラスを取得することです。だから私は次のようなことをしました:CodeElementがプロジェクトに属しているかどうかを確認

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

これは、クラスを通過して引き出します。問題は、参照されるすべてのものにBCLクラスが含まれていることです。私はInfoLocationを使用すると助けになると思いましたが、すべてがvsCMInfoLocationExternalを返します(おそらく、プラグインが実行されているコンテキストでは、外部にあるためです)。私はelement.ProjectItemelement.ProjectItem.ContainingProjectelement.Parentのようなものを親プロジェクトと比較することを望んで試しましたが、それらはすべてSystem.Runtime.InteropServices.COMExceptionを投げます。プロジェクトを知っているので、特定のCodeElementがプロジェクトの一部であるのか、それともプロジェクトによって参照されているのかを判断する方法はありますか?

EDIT:最高のは、私がこれまでに出てくることができましたが、これを行うことです、最初のプロジェクトのデフォルトの名前空間を取得:

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

をそして私はこれを行うことができます。

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

ここでは、私はSystemにドリルダウンしません。これは良いことです。唯一の問題は、プロジェクトに複数の名前空間があり、検索したい場合です。プロジェクト内にと定義されている名前空間のリストを取得する方法があるかどうかはわかりません。

編集:提案された二重引用符はTypeを扱うので、完全には関連しません。

+2

私はhttp://stackoverflow.com/questions/3174921/how-do-i-determine-if-system-type-is-a-custome-type-orのDUPとしてこれをマーキングしています-a-framework-typeを使用することはできません。なぜなら、これをvs拡張モジュールの内部または外部で行う方法がないからです。 –

+0

@PaulSwetz:それを行う方法はないかもしれませんが、提案されたデュプリは同じものではなく、ここでは役立ちません。私は 'Type'を持っていない、' CodeElement'を持っているので、 'Type'を含む提案は関係ありません。 –

+0

ソリューション定義の外部参照と比較してコード要素内で見つかるどのようなクラス/ enum/structsかを調べることで、あなたが望むことを実行できるという答えを出すことができます。 *あなたのニーズに合っているかもしれませんが、非常に効率的だとは言えませんが、再帰性が高いからです。 –

答えて

1

これはあなたのニーズに合っているかもしれませんが、これは私がコード要素を解析し、定義が解決策に含まれているかどうか、または参照によって得られるかどうかを調べるために使用したものです。リファレンスが第三者vs BCLかどうかを知る方法はありません。いくつかのコードは簡潔さのために削除されています。これはAPIの中にあり、完全に壊れにくいからです。あなたはタイプのフルネームを持っていればトリックを追加することができますし、bclを見つけたらタイプ名のMicrosoftキーで署名されたすべてのdllを反映するリファレンスを知っています。そうでなければでしょう。

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); 
    } 
} 
関連する問題