在開發的項目的時候,你是否經常遇到需要重復編寫一些類似的代碼,比如是否經常會使用 for、foreach ? 在編寫這兩個循環語句的時候,你是一個字符一個字符敲還是使用 Visual Studio 提供的Code Snippet 工具自動幫你生成呢?
神奇之處
你只需要在代碼編輯器中輸入for,就會看到 Visual Studio 的自動提示框中出現了如下紅框框起來的部分,這個時候只需要連按兩下 tab 鍵,便會自動補全 for 循環語句(如圖2所示),並且默認選中索引,以便你進行修改。
圖 1 自動提示框
圖 2 自動補全循環語句
是不是很神奇? 與之類似的還有switch、cw (Console.WriteLine)、ctor(構造器)、prop(屬性)等,靈活運用這些就可以讓你的 Coding 工作事半功倍,更多默認 CodeSnippet 請查看參考資源[1]。
但是,每個項目都有每個項目的特殊性,默認的這些 Code Snippet 如果無法滿足您的需求,這個時候就需要自動動手來擴展了。
Code Snippet 的神秘面紗【C#】
在動手開始寫自己的 Code Snippet 之前,得先搞清楚這個玩意兒是怎么做到的。
它其實只是一個 xml,只不過包含了一些只有 Visual Studio 才認識的元素,這些元素就定義了如何去替我們補全代碼(,Code Snippet 針對不同的語言如VB、C#、CSS使用不同的元素,本文全部按照 C# 語言進行介紹)。
下面來看一下 for 的Snippet源代碼是長什么樣子的
1 <?xml version="1.0" encoding="utf-8"?> 2 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 3 <CodeSnippet Format="1.0.0"> 4 <Header> 5 <Title>for</Title> 6 <Shortcut>for</Shortcut> 7 <Description>for 循環的代碼段</Description> 8 <Author>Microsoft Corporation</Author> 9 <SnippetTypes> 10 <SnippetType>Expansion</SnippetType> 11 <SnippetType>SurroundsWith</SnippetType> 12 </SnippetTypes> 13 </Header> 14 <Snippet> 15 <Declarations> 16 <Literal> 17 <ID>index</ID> 18 <Default>i</Default> 19 <ToolTip>索引</ToolTip> 20 </Literal> 21 <Literal> 22 <ID>max</ID> 23 <Default>length</Default> 24 <ToolTip>最大長度</ToolTip> 25 </Literal> 26 </Declarations> 27 <Code Language="csharp"><![CDATA[for (int $index$ = 0; $index$ < $max$; $index$++) 28 { 29 $selected$ $end$ 30 }]]> 31 </Code> 32 </Snippet> 33 </CodeSnippet> 34 </CodeSnippets>
一個 CodeSnippet 則主要包含 <Header> 和 <Snippet> 兩部分。上面的結構挺清晰的,一個 <CodeSnippets> 元素可以包含多個不同的 <CodeSnippet> 。
其中 <Header> 部分主要是對這個 Snippet 的一個聲明,包括 Snippet 的名稱、描述、作者及 Snippet 的類型(稍后會解釋)。
Header 部分在實際運行中的作用
<Snippet> 元素
snippet元素是關鍵的重點,單獨弄一節來具體說明。
完整的 snippet 元素結構如下:
1 <Snippet> 2 <Declarations>... </Declarations> 3 <Code>... </Code> 4 </Snippet>
<Declarations> 元素
該元素用於定義在運行中需要被替換的變量,Microsoft 提供了兩種類型:Literal(文本)和 Object(對象)。MSDN上的解釋如下:
Literal 元素用於標識整體包含在代碼段中、但在插入到代碼中后可能會進行自定義的代碼部分的替換對象。例如,字符串、數字值以及應聲明為文本的一些變量名。
Object 元素用於標識代碼段所需的、但可能是在代碼段外部定義的項。例如,Windows 窗體控件、ASP.NET 控件、對象實例以及類型實例應聲明為對象。對象聲明需要指定類型。
至於這兩者在實際運用中的區別,我還真不清楚。如果哪位大俠對此了解,還望指點一二。下面只介紹 Literal 類型。
完整的 <Literal> 結構如下:
1 <Literal Editable="true/false"> 2 <ID>... </ID> 3 <ToolTip>... </ToolTip> 4 <Default>... </Default> 5 <Function>... </Function> 6 </Literal>
ID 用於指定需要被替換的對象名稱,有且只有一個。Editable 意味在生成代碼過程中能不能直接替換成我們想要文本,比如 for 循環中的索引變量,默認是 “i”,但是我們可以替換成任何自己想要的,比如 “Index”。
Default 表示默認生成代碼時,該對象將被 Default 值給代替。
Function 指示當該對象在獲取焦點的時候將要執行的方法。在 Visual Studio 中目前只支持三個方法:GenerateSwitchCases(EnumerationLiteral)、ClassName()、SimpleTypeName(TypeName)。
其中 GenerateSwitchCases 顧名思義是用於為switch的變量生成case條件的。
ClassName方法用於獲取當前的類名。
SimpleTypeName 則用於縮短類型的名字,因為有些時候有些程序集不會被using進來,這個時候對該程序集中某一類型的調用就需要使用 “名稱空間.類型名稱” 這種方式。但是如果當前的文件已經把需要的程序集using進來了,那這種調用方式就顯得是多此一舉。通過使用 SimpleTypeName 就能在生成代碼的時候幫助我們判斷是否需要加上名稱空間這個前綴。
<Code> 元素
這才是我們的主角,因為我們的代碼就是寫在了該元素內部。先來看一個例子:
1 <Code Language="csharp"><![CDATA[for (int $index$ = 0; $index$ < $max$; $index$++) 2 { 3 $selected$ $end$ 4 }]]>
上面的代碼相當簡單,所有需要在生成代碼的時候被替換的內容都用 $ 包裹,如$index$,記住這個被包裹的內容必須在 <Declarations> 被正確定義過。因為代碼中可能會有一些在XML中有特殊含義的字符,所以用CDATA進行包裹,防止錯誤轉義。
$selected$ 和 $end$ 是保留的關鍵字,其中 $end$ 用於指示當代碼插入完畢后,光標應該位於的位置。$selected$ 用於表示在生成代碼前你所選中的文本,並在生成代碼的過程中使用你選中的文本替換 $selected$,常用於 SurroundWith 這種類型的 Code Snippet 中。
Snippet 類型
根據我們的使用方式,snippet 分為 Expansion、SurroundsWith 及 Refactoring(只能在重構過程中使用,自定義的 Code Snippet 不能使用)。
Expansion:允許將代碼段插入到光標處。
SurroundsWith:允許將此代碼段放置在一段選定的代碼周圍。比如我們寫完一段代碼后,發現忘記加 try...catch... 了,這個時候可以選中需要包裹在 try...catch... 中的代碼,然后調用 Code Snippet。
如何自定義一個 snippet
如果對上面的結構有了基本了解,下面就來實踐一下吧。通過本節,我們要實現自動生成 Debug.WriteLine 的 snippet。
首先,打開 Visual Stuido / 文件 / 新建 / 文件,選擇 xml 類型。
在 xml 文件中,輸入最小的snippet代碼。
1 <?xml version="1.0" encoding="utf-8"?> 2 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 3 <CodeSnippet Format="1.0.0"> 4 <Header> 5 <Title></Title> 6 </Header> 7 <Snippet> 8 <Code Language=""> 9 <![CDATA[]]> 10 </Code> 11 </Snippet> 12 </CodeSnippet> 13 </CodeSnippets>
修改如上的代碼,包括 Header 部分和 Snippet 部分,別忘記指定Language。
1 <?xml version="1.0" encoding="utf-8"?> 2 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 3 <CodeSnippet Format="1.0.0"> 4 <Header> 5 <Title>dw</Title> 6 <Description>Debug.WriteLine</Description> 7 <Shortcut>dw</Shortcut> 8 <Author>Charley</Author> 9 </Header> 10 <Snippet> 11 <Declarations> 12 <Literal> 13 <ID>text</ID> 14 <ToolTip>希望輸出的內容</ToolTip> 15 <Default>"text"</Default> 16 </Literal> 17 </Declarations> 18 <Code Language="csharp"> 19 <![CDATA[Debug.WriteLine($text$);$end$]]> 20 </Code> 21 </Snippet> 22 </CodeSnippet> 23 </CodeSnippets>
如果嫌自己寫太麻煩,也可以使用開源的 snippet 編輯工具,詳見參考資源[2]。
Snippet 的管理
新建完一個snippet之后,該如何才能在項目中用起來呢?
工具 / 代碼段管理器 打開管理器。
使用 “導入” 將自定義的文件導入進來。
為自己的 snippet 選擇一個位置。
點擊完成就已經成功了。在代碼編輯器中,輸入 dw 就會發現 Visual Stuido 的智能提示已經出現了我們的 snippet。
如何使用 SurroundWith 類型的 Snippet?
相比於 Expansion 類型的 snippet,使用 SurroundsWith 相對要麻煩點。
本人認為最快捷的方式就是使用鍵盤快捷鍵,在代碼編輯器中 CTRL+K, CTRL+S,就可以呼出 snippet。
然后用鍵盤或鼠標選擇目標 snippet。
參考資源
[2] Snippet Editor