确定CodeElement是否属于项目
本文关键字:项目 属于 是否 CodeElement 确定 | 更新日期: 2023-09-27 17:58:03
我正在尝试为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.ProjectItem
、element.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
,因此并不完全相关。
这可能适合您的需求,也可能不适合,但这是我用来解析代码元素并确定定义是否在解决方案中或是否通过引用来的。然而,没有办法知道参考是否是第三方与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);
}
}