C# 确定CodeElement是否属于项目

C# 确定CodeElement是否属于项目,c#,visual-studio-extensions,envdte,C#,Visual Studio Extensions,Envdte,我正在尝试为VisualStudio2015开发一个插件。我有一个命令,当右键单击一个项目时,它会被添加到上下文菜单中,我可以得到右键单击的项目。现在我要做的是确定项目是否包含实现某个接口的类。因此,我的第一步是获取项目中的类。所以我做了这样的事情: protected IEnumerable<EnvDTE.CodeClass> GetClasses(EnvDTE.CodeElements elements,

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

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;
            }
        }
    }
}
然后我可以这样做:

if (ns != null && ns.Name == defaultNS)
所以现在我不再深入研究
系统
,这很好。唯一的问题是,如果一个项目有多个我想要搜索的名称空间。我不知道是否有办法获得项目中定义的名称空间列表


编辑:建议的dupe处理
类型
,因此并不完全相关。

这可能适合您的需要,也可能不适合您的需要,但这就是我用来解析代码元素并确定定义是在解决方案中还是通过引用引入的。但是,无法知道该参考是第三方还是BCL。为了简洁起见,删除了一些代码,因为这些代码在API中,很难完全破解。您可以添加一个技巧,一旦您拥有类型全名并知道它是一个引用,您可以在其中反映所有使用Microsoft密钥签名的DLL作为类型名,如果您找到它的bcl,否则它可能不是

public静态字符串codelementastypefullname(EnvDTE80.codelement2元素)
{
if(元素==null)
抛出新ArgumentNullException(nameof(element));
如果(element.Kind==vsCMElement.vsCMElementClass
||element.Kind==vsCMElement.vsCMElementEnum
||element.Kind==vsCMElement.vsCMElementStruct)
返回element.FullName;
其他的
返回((动态)元素);
}
受保护的元素(EnvDTE80.CodeElement2元素)
{                        
尝试
{
字符串varType=codelementastypefullname(元素);
开关(元件种类)
{
案例vsCMElement.vsCMElement变量:
案例vsCMElement.vsCMElementProperty:
{
EnvDTE80.CodeElement2已定义=空;
///这是API,基本上是解决方案中所有文件的集合,所有class/enum/stuct def都解析为集合。
foreach(此.solutionFiles中的SquishFile文件)
{
//下一行逐个遍历每个解决方案文件,以确定该文件是否定义了类/枚举/结构定义。
定义=file.ContainsCodeElement(varType);
如果(已定义!=null)
打破
}
如果(已定义!=null)
{
if(defined.Kind==vsCMElement.vsCMElementClass
||defined.Kind==vsCMElement.vsCMElementStruct
||defined.Kind==vsCMElement.vsCMElementEnum)
//该项是本地定义的!
}否则
//该项目是一个参考
}
}
}
公共类压缩文件
{        
public ConcurrentBag ClassDefinitions=新ConcurrentBag();
public ConcurrentBag EnumDefinitions=新ConcurrentBag();
public ConcurrentBag StructDefinitions=新ConcurrentBag();
受保护项目(projecttem);;
公共ProjectItem ProjectItem{get{return\u ProjectItem;}}
公共压缩文件(ProjectItem ProjectItem)
{
if(projectItem.FileCodeModel==null)
抛出新异常(“无法从没有FileCodeModel的项目项中生成压缩文件!”);
_projectItem=projectItem;
foreach(projectItem.FileCodeModel.CodeElements中的EnvDTE80.CodeElement2 ele)
发现(ele);
}
public EnvDTE80.codelement2包含deelement(字符串全名)
{
foreach(类定义中的EnvDTE80.codelement2 ele)
if(ele.FullName.Equals(FullName))
返回ele;
foreach(枚举定义中的EnvDTE80.codelement2 ele)
if(ele.FullName.Equals(FullName))
返回ele;
foreach(结构定义中的EnvDTE80.CodeElement2元素)
if(ele.FullName.Equals(FullName))
返回ele;
返回null;
}
受保护的无效发现(EnvDTE80.CodeElement2元素)
{
if(element.IsCodeType&&element.Kind==vsCMElement.vsCMElementClass)
this.ClassDefinitions.Add(元素为EnvDTE80.CodeClass2);
else if(element.IsCodeType&&element.Kind==vsCMElement.vsCMElementEnum)
this.EnumDefinitions.Add(元素为EnvDTE.CodeEnum);
else if(element.IsCodeType&&element.Kind==vsCMElement.vsCMElementStruct)
this.StructDefinitions.Add(元素为EnvDTE80.CodeStruct2);
foreach(EnvDTE80.codelement2 ele-in-element.Children)
发现(ele);
}
}

我将此标记为dup of,因为在vs扩展内部或外部都无法执行此操作。@PaulSwetz:可能没有执行此操作的方法,但建议的dup不是同一件事,在这里没有帮助。我没有
类型
,我有
代码元素
,因此建议使用
类型
不相关。我可以给出一个答案,通过计算它在codeelement中遇到的类/枚举/结构来自外部引用,而不是解决方案定义。它可能适合您的需要,但不能说它非常有效,因为它是高度递归的。
if (ns != null && ns.Name == defaultNS)
 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);
    }
}