确定CodeElement是否属于项目

时间:2016-07-21 20:01:00

标签: c# visual-studio-extensions envdte

我正在尝试为Visual Studio 2015开发一个插件。当右键单击项目时,我会将命令添加到上下文菜单中,我可以获得右键单击的项目。现在我要做的是确定项目是否包含实现某个接口的类。所以我的第一步是获取项目中的类。所以我做了这样的事情:

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.ContainingProject以及element.Parent之类的内容,希望将其与父项目进行比较,但这些内容都会抛出System.Runtime.InteropServices.COMException。那么,鉴于我知道项目,有没有办法确定特定的CodeElement是否属于项目的一部分,或者只是由项目引用?

编辑:到目前为止,我能够做到的最好的方法是首先获得项目的默认命名空间:

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

然后我可以这样做:

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

所以现在我不打算深入System,这很好。唯一的问题是如果一个项目有多个我想要搜索的命名空间。我无法弄清楚是否有办法获得项目中定义的名称空间列表

修改:建议的欺骗行为与Type有关,因此并非完全相关。

1 个答案:

答案 0 :(得分:1)

这可能适合您的需要,也可能不适合,但这是我用于解析代码元素并确定定义是否在解决方案中或者是否通过引用传入的内容。然而,无法知道引用是否是第三方与BCL。为简洁起见,删除了一些代码,因为这是在API中并且难以完全突破。一旦你有了类型的全名你就可以添加一个技巧,并且知道它的引用你反映所有用类型名称的Microsoft键签名的dll,如果你找到一个bcl,否则它可能不是。

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