4

我試圖在Visual Studio 2008中使用宏(甚至是加載項)在代碼窗口的某個點(光標)上解析ac#標識符的完全限定名。如何檢索VS宏中標識符的完全限定名?

例如,如果遊標在「Rectangle」中,我想返回「System.Drawing.Rectangle」。

我試過FileCodeModel.CodeElements.CodeElementFromPoint但他們只檢索包含的方法或類(和其他人)。

如果這不能使用宏或加載項來完成(即使VS通過intellisense知道信息),是否可以在c#文件中使用Reflection讀取並獲取所需的信息?

回答

7

它可以做到。這裏有一個解決方案(雖然有點不太好):使用F1幫助上下文。爲了使F1幫助工作,Visual Studio將當前選擇或插入點的完全限定類型名稱壓入一個名爲「F1幫助上下文」的名稱/值對中。並且在Visual Studio SDK中有用於查詢F1幫助上下文內容的公共API。

爲了保持理智,您需要啓用F1幫助上下文的調試註冊表項。這可以讓您隨時通過常用的動態幫助窗口查看幫助上下文中的內容。要做到這一點:

  1. 啓動visual studio,並從幫助菜單中選擇動態幫助。
  2. 設置下面的註冊表項(您需要一步#1創建註冊表樹)
  3. 重新啓動Visual Studio拿起改變現在
  4. ,在動態幫助窗口會有調試輸出,所以你可以看到F1有助於上下文。本答案的其餘部分描述瞭如何以編程方式獲取該上下文,以便您的加載項可以使用它。

這裏的註冊表項:

[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Dynamic Help] 
"Display Debug Output in Retail"="YES" 

正如你從看F1調試輸出中看到,Visual Studio中沒有明確告訴你「這是識別的類型」。相反,它只需將完全限定的類型名稱粘貼到F1用於提供幫助的一個或多個「幫助關鍵字」的開頭。例如,您可以在幫助上下文中使用System.String,VS.TextEditor和VS.Ambient,並且只有第一個與當前代碼有關。

使這個更容易的訣竅是:Visual Studio可以將關鍵字標記爲區分大小寫或不區分大小寫。 AFAIK是Visual Studio中唯一注入區分大小寫關鍵字的部分,它是對代碼上下文進行響應的區分大小寫語言(C#,C++)的代碼編輯器。因此,如果您將所有關鍵字過濾爲區分大小寫的關鍵字,則您知道您正在查看代碼。

不幸的是,如果插入點位於語言關鍵字之上,C#編輯器還會將語言關鍵字(不僅僅是標識符)推入幫助上下文中。所以你需要篩選出語言關鍵字。有兩種方法可以做到這一點。你可以簡單地嘗試在類型系統中查找它們,並且由於它們不是有效的類型名稱(尤其不是VS對它們進行修改的方式,例如string關鍵字的「string_CSharpKeyword」),所以你可以靜靜地失敗。或者你可以檢測到缺少點並假定它不是類型名稱。或者你可以檢測到_CSharpKeyword後綴,並希望VS團隊不會改變它。 :-)

另一個潛在的問題是泛型。你會從VS得到一個泛型類型的類型名稱看起來是這樣的:

System.Collections.Generic.List`1 

和方法是這樣的:

System.Collections.Generic.List`1.FindAll. 

你需要聰明地檢測反勾號並處理它。

此外,在ASP.NET MVC .ASPX文件中,您可能會在頁面上同時存在C#代碼和其他區分大小寫的代碼(例如,javascript)的情況下獲得有趣的行爲。在這種情況下,您還需要查看屬性。除關鍵字外,「幫助上下文」還具有「屬性」,它們是描述當前上下文的名稱/值對。例如,devlang = csharp是一個屬性。下面的代碼也可以用來提取屬性。你需要嘗試找出正確的屬性來尋找,所以你最終不會採用JavaScript或其他奇怪的代碼。

無論如何,現在你已經理解(或者至少已經暴露了!)所有的注意事項,這裏有一些代碼從幫助上下文中提取區分大小寫的關鍵字(如果存在的話)以及其餘部分名稱/值對。 (關鍵字只是名稱爲「關鍵字」的名稱/值對)。

請記住,爲了獲得Microsoft.VisualStudio.Shell.Interop,Microsoft.VisualStudio.Shell和Microsoft,此代碼需要Visual Studio SDK(不只是常規的VS安裝)才能構建。 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"); 
     } 
    } 
} 
+0

非常感謝,這個作品完美! – ste 2009-09-24 12:39:57

相關問題