2016-07-21 5 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이 프로젝트의 일부인지 아니면 프로젝트가 참조한 것인지를 결정하는 방법이 있습니까?

편집 : 최선은 내가 지금까지 가지고 올 수있었습니다이 작업을 수행하는 것입니다, 먼저 프로젝트의 기본 네임 스페이스 얻을 :

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을 사용할 수 있습니다. 왜냐하면 실제로이 작업을 대용량 확장의 내부 또는 외부에서 수행 할 방법이 없기 때문입니다. –

+0

@ PaulSwetz : 그렇게 할 방법이 없을 수도 있지만 제안 된 속임수는 똑같지 않으며 여기서는 도움이되지 않습니다. 나는'Type'을 가지고 있지 않습니다.'CodeElement'을 가지고 있으므로,'Type'과 관련된 제안은 관련이 없습니다. –

+0

나는 해결책에 대해 외부 참조와 솔루션 정의에서 오는 codeelement에서 만나는 클래스/열거 형/구조체를 알아 내서 원하는 것을 수행 할 수 있습니다. 그것은 아마도 여러분의 필요에 맞을 수도 있습니다. 매우 재귀 적이기 때문에 매우 효율적이라고 말할 수는 없습니다. –

답변

1

이것은 사용자의 요구에 맞을 수도 있지만 그렇지 않을 수도 있습니다. 그러나 이것은 코드 요소를 구문 분석하고 정의가 솔루션에 있는지 또는 참조를 통해 제공되는지 파악하는 데 사용됩니다. 그러나 참조가 제 3 자 대 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); 
    } 
}