C# 如何在VS宏中检索标识符的完全限定名?

C# 如何在VS宏中检索标识符的完全限定名?,c#,visual-studio-2008,macros,intellisense,visual-studio-addins,C#,Visual Studio 2008,Macros,Intellisense,Visual Studio Addins,我试图在VisualStudio2008中使用宏(甚至外接程序)解析代码窗口某个点(光标)上的c#标识符的完全限定名 例如,如果光标位于“矩形”中,我希望返回“System.Drawing.Rectangle” 我尝试了FileCodeModel.codelements和.codelementfrompoint但它们只检索包含的方法或类(以及其他) 如果无法使用宏或外接程序完成此操作(即使VS通过intellisense知道信息),是否可以使用c文件中读取的反射并获得所需信息?可以完成此操作。这

我试图在VisualStudio2008中使用宏(甚至外接程序)解析代码窗口某个点(光标)上的c#标识符的完全限定名

例如,如果光标位于“矩形”中,我希望返回“System.Drawing.Rectangle”

我尝试了
FileCodeModel.codelements
.codelementfrompoint
但它们只检索包含的方法或类(以及其他)


如果无法使用宏或外接程序完成此操作(即使VS通过intellisense知道信息),是否可以使用c文件中读取的反射并获得所需信息?

可以完成此操作。这里有一个解决方案(尽管有点老套):使用F1帮助上下文。为了使F1帮助工作,Visual Studio将当前选择或插入点的完全限定类型名称推入名为“F1帮助上下文”的名称/值对包中。VisualStudioSDK中有用于查询F1帮助上下文内容的公共API

为了保持理智,您需要为F1帮助上下文启用调试注册表项。这使您可以随时通过经常被诟病的动态帮助窗口查看帮助上下文中的内容。为此:

  • 启动visual studio并从“帮助”菜单中选择“动态帮助”
  • 在下面设置注册表项(创建注册表树需要步骤#1)
  • 重新启动Visual Studio以获取更改
  • 现在,在动态帮助窗口中将有调试输出,以便您可以查看F1帮助上下文中的内容。此答案的其余部分描述如何以编程方式获取该上下文,以便外接程序可以使用它 这是注册表项:

    [HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Dynamic Help]
    "Display Debug Output in Retail"="YES"
    
    从F1调试输出中可以看出,VisualStudio没有明确地告诉您“这是标识符的类型”。相反,它只是将完全限定的类型名称粘贴在F1用来显示帮助的一个或多个“帮助关键字”的开头。例如,在帮助上下文中可以有System.String、VS.TextEditor和VS.Ambient,并且只有第一个与当前代码相关

    使这更容易的技巧是:VisualStudio可以将关键字标记为区分大小写或不区分大小写。AFAIK是visualstudio中唯一注入区分大小写关键字的部分,它是区分大小写语言(C#,C++)的代码编辑器,用于响应代码上下文。所以,如果您将所有关键字筛选为区分大小写的关键字,您就知道您正在查看代码

    不幸的是,如果插入点位于语言关键字之上,C#编辑器还会将语言关键字(不仅仅是标识符)推送到帮助上下文中。因此,您需要筛选出语言关键字。有两种方法可以做到这一点。您可以简单地尝试在类型系统中查找它们,因为它们不是有效的类型名称(尤其不是VS对它们的处理方式,例如字符串关键字的“string_CSharpKeyword”),所以您可以默默地失败。或者,您可以检测到缺少点,并假设它不是类型名。或者您可以检测到_CSharpKeyword后缀,并希望VS团队不会更改它。:-)

    另一个潜在问题是泛型。对于泛型类型,您将从VS获得的类型名称如下所示:

    System.Collections.Generic.List`1 
    
    System.Collections.Generic.List`1.FindAll.
    
    方法如下所示:

    System.Collections.Generic.List`1 
    
    System.Collections.Generic.List`1.FindAll.
    
    你需要聪明地发现并处理它

    此外,在ASP.NET MVC.ASPX文件中,页面上同时存在C#代码和其他区分大小写的代码(例如javascript),您可能会看到一些有趣的行为。在这种情况下,您还需要查看属性。除了关键字之外,帮助上下文还具有“属性”,即描述当前上下文的名称/值对。例如,devlang=csharp是一个属性。下面的代码也可以用来提取属性。您需要进行实验,找出要查找的正确属性,这样您就不会在javascript或其他奇怪的代码上执行操作

    无论如何,现在您已经理解(或者至少已经了解了!)所有的警告,下面是一些代码,可以从帮助上下文以及其他名称/值对中提取区分大小写的关键字(如果存在)。(关键字只是名称为“关键字”的名称/值对)

    请记住,此代码需要Visual Studio SDK(不仅仅是常规的VS安装)才能进行构建,以便获得Microsoft.VisualStudio.Shell.Interop、Microsoft.VisualStudio.Shell和Microsoft.VisualStudio.OLE.Interop命名空间(您需要在加载项项目中添加这些命名空间作为引用)

    好的,祝你玩得开心,好运

    using System;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
    using System.Resources;
    using System.Reflection;
    using System.Globalization;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.OLE.Interop;
    using System.Collections.Generic;
    
    public class HelpAttribute
    {
        public string Name;
        public string Value;
        public VSUSERCONTEXTPRIORITY Priority;
        public VSUSERCONTEXTATTRIBUTEUSAGE Usage;
    }
    
    public class HelpContext2 : List<HelpAttribute>
    {
        public static HelpContext2 GetHelpContext(DTE2 dte)
        {
            // Get a reference to the current active window (presumably a code editor).
            Window activeWindow = dte.ActiveWindow;
    
            // make a few gnarly COM-interop calls in order to get Help Context 
            Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)activeWindow.DTE;
            Microsoft.VisualStudio.Shell.ServiceProvider serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(sp);
            IVsMonitorUserContext contextMonitor = (IVsMonitorUserContext)serviceProvider.GetService(typeof(IVsMonitorUserContext));
            IVsUserContext userContext;
            int hresult = contextMonitor.get_ApplicationContext(out userContext);
            HelpContext2 attrs = new HelpContext2(userContext);
    
            return attrs;
        }
        public HelpContext2(IVsUserContext userContext)
        {
            int count;
            userContext.CountAttributes(null, 1, out count);
            for (int i = 0; i < count; i++)
            {
                string name, value;
                int priority;
                userContext.GetAttributePri(i, null, 1, out priority, out name, out value);
                VSUSERCONTEXTATTRIBUTEUSAGE[] usageArray = new VSUSERCONTEXTATTRIBUTEUSAGE[1];
                userContext.GetAttrUsage(i, 1, usageArray);
                VSUSERCONTEXTATTRIBUTEUSAGE usage = usageArray[0];
                HelpAttribute attr = new HelpAttribute();
                attr.Name = name;
                attr.Value = value;
                attr.Priority = (VSUSERCONTEXTPRIORITY)priority;
                attr.Usage = usage; // name == "keyword" ? VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Lookup : VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter;
                this.Add(attr);
            }
        }
        public string CaseSensitiveKeyword
        {
            get
            {
                HelpAttribute caseSensitive = Keywords.Find(attr => 
                    attr.Usage == VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_LookupF1_CaseSensitive
                    || attr.Usage == VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Lookup_CaseSensitive
                    );
                return caseSensitive == null ? null : caseSensitive.Value;
            }
        }
        public List<HelpAttribute> Keywords
        {
            get
            {
                return this.FindAll(attr=> attr.Name == "keyword");
            }
        }
    }
    
    使用系统;
    使用可扩展性;
    使用EnvDTE;
    使用EnvDTE80;
    使用Microsoft.VisualStudio.CommandBars;
    利用系统资源;
    运用系统反思;
    利用制度全球化;
    使用Microsoft.VisualStudio.Shell.Interop;
    使用Microsoft.VisualStudio.Shell;
    使用Microsoft.VisualStudio.OLE.Interop;
    使用System.Collections.Generic;
    公共类帮助属性
    {
    公共字符串名称;
    公共字符串值;
    公共VSUSERCONTEXTPRIORITY优先级;
    公共VSUSERCONTEXTATTRIBUTEUSAGE;
    }
    公共类HelpContext2:列表
    {
    公共静态HelpContext2 GetHelpContext(DTE2 dte)
    {
    //获取对当前活动窗口的引用(可能是代码编辑器)。
    Window-activeWindow=dte.activeWindow;
    //进行一些粗糙的COM互操作调用以获取帮助上下文
    Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp=(Microsoft.VisualStudio.OLE.Interop.IServiceProvider)activeWindow.DTE;
    Microsoft.VisualStudio.Shell.ServiceProvider ServiceProvider=新的Microsoft.VisualStudio.Shell.ServiceProvider(sp);
    IVsMonitorUserContext上下文监视器=(IVsMonitorUserContext)serviceProvider.GetService(typeof(IVsMonitorUserContext));
    IVsUserContext用户上下文;
    int hresult=contextMonitor.get_ApplicationContext(out userContext);
    HelpContext2 attrs=新建