Code Snippet
Code Snippet,與其稱其為代碼片段(Code Block),將它翻譯成代碼模板(Code Template)可能更合適一些。
任何一段代碼都可以叫做代碼片段,我們這里要講的不是這種隨性的東西,而是一種快速生成代碼的快捷方式,通過它可以有效地提高我們的編程效率。
舉個例子,假如你在C#代碼編輯器中輸入propfull
,再連續摁倆下Tab
鍵進行代碼補全,將會自動為你生成以下代碼段:
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
編輯器里是這樣子的:
此時光標處於第一個int
位置,鍵入任何其他類型都會置換int
,並且你可以通過Tab
鍵位跳到下一個可修改的地方(背景色為黃色),這個模板里提供了3個可修改的位置,int
,myVar
以及MyProperty
。
當你修改myVar的時候,你可以通過"Alt+Enter"或者"Ctrl+."將其他引用了myVar的地方進行快速替換。
你僅僅通過輸入幾個字符,就完成了一大段代碼的創建,為你省下不少時間,試想一下你創建過的封裝屬性何其的多,僅這一項就可以大大的提高你的工作效率。
你也通過其他的第三方擴展或者通過"快速操作->封裝字段"也可以實現類似的效果。
Microsoft為你內置了不少語言的不少代碼模板,如下圖所示是C#內置的Code Snippet:
我們可以按位置在本地找到相應的代碼片段,都是.snippet
文件,我們用記事本打開propfull.snippet
文件,里面的內容如下所示:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propfull</Title>
<Shortcut>propfull</Shortcut>
<Description>屬性和支持字段的代碼片段</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>屬性類型</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>屬性名</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>支持此屬性的變量</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set { $field$ = value;}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
雖然你也可以通過直接修改這個xml文檔來修改代碼模板,但我們更推薦使用Visual Studio的一個可視化擴展,叫Snippet Designer。它可以讓你更加容易地進行代碼模板的編輯,至於上面的內容每一段具體都是什么意思我們將在后面一一介紹。
Snippet Designer 安裝
你可以通過以下的方法安裝Snippet Designer:
-
在Visual Studio的擴展管理器里,直接通過聯網搜索下載Snippet Designer,安裝完后需要重啟。
-
在https://marketplace.visualstudio.com/items?itemName=vs-publisher-2795.SnippetDesigner上下載SnippetDesigner.vsix,下載完成后雙擊進行安裝,注意安裝時不能有打開的VS實例。
-
你也可以在Github上下載其解決方案然后自己編譯安裝,倉庫地址為:https://github.com/mmanela/SnippetDesigner。
注意你需要在"菜單->工具->選項->擴展"中勾選上"允許同步自動加載擴展",如果不勾,我的VS2019完全用不了這個擴展,不知道其它版本的VS如何。
Snippet Designer 特性
按照Github上的介紹文檔說的是:
Access it by opening any .snippet file or going to File -> New -> File -> Code Snippet File.
也就是說,首先你可以通過新建文件的時候創建snippet文件,本來應該這樣子的:
而事實上我的是這樣子的,啥也沒有:
It uses the native Visual Studio code editor so that you can write the snippets in the same enviorment you write your code.
嗯,這點倒是可以,后續你就可以看到,就跟普通文檔一樣編寫代碼。
It lets you easily mark replacements by a convenient right click menu.
這點也沒問題,就是編輯模板的時候,選中一塊你想替換的內容,右鍵菜單里有個Make Replacement選項,如下所示:
It displays properties of the snippet inside the Visual Studio properties window.
確實,也提供了一個屬性窗口,如下所示:
It is located under View -> Other Windows -> Snippet Explorer.
你可以打開"菜單->視圖->其它窗口->Snippet Explorer",如下圖所示:
本來應該長這樣子的:
而我在VS2019下打開的是這樣子,啥都沒有:
This tool window contains a code preview window which lets to peek inside the snippet to see what it is without opening the file.
說的是"菜單->工具->代碼片段管理器"窗口,提供了一個快速預覽的功能,但跟這個擴展沒啥關系。
Maintains an index of snippets on your computer for quick searching.
在你機器上為所有的snippets文件創建了索引以便快速訪問,感覺不出來有沒有這效果。
Provides a quick way to find a code snippet to use, edit or delete.
應該說的是"Snippet Explorer"功能,反正我這沒有,安裝完成后先是提示了"Visual Studio無法同步加載某些擴展",然后我手動去工具選項那勾選了允許同步加載,又提示"VS在加載擴展的過程中無法調用已經過時了的API"。
The Snippet Designer supports Visual Studio 2015, 2017, 2019.
不是說好的支持VS2019嗎?難道我裝的是假的VS2019企業版。
Snippet Designer 詳細介紹
雖然我的VS2019並不能用到上面介紹的所有特性,但不代表在座各位帥哥美女不行,又或者其它版本的VS能穩定支持也說不一定呢。
我的目標始終是編寫代碼模板來加快自己的編程效率,他提供的那些特性為什么在我的這個機器環境基本用不了,我也不接着折騰了,假如有那位大佬解決了這個問題,請告訴我一聲,我學習一下。
但有一個沒提到的功能它是肯定能用的,而接下來我也將用這個功能來演示如何創建代碼模板,以及我在查看系統內置模板后總結出來的一點點心得。
你可以在任意一個代碼文件里選中一段代碼,然后右鍵菜單中選擇"Export as Snippet":
這意味着你打算將這段代碼轉成代碼模板,然后就會跳轉到這樣的一個窗口:
我先稍作修改,然后我們再解釋:
紅框部分和綠底部分都是我們做了修改的,通過"代碼片段管理器",你可以很輕松的對應上相應的描述字段,這些我們不用多做解釋,大家都懂,值得一提的是,你存儲Snippet的文件名可以是任何名字,不過建議和快捷方式(shortcut)一致,這樣子容易找。接下來我們解釋最重要的部分:
- shortcut:快捷方式,這里是
tryccf
,也就是說你通過在代碼編輯器里敲擊這個tryccf
快捷方式,再通過兩次Tab
補全,就能完全顯示與上面一樣的內容。假如你定義的快捷方式和其他快捷方式重了,你在代碼編輯器里使用的時候,會彈出選擇框讓你選擇想要的代碼模板。 - $selected$:當你通過"選中一段代碼->右鍵菜單->片段->外部代碼->選中相應的代碼片段后",被選中的代碼會被包裹在
$selected$
定義的位置里。 - $end$:假如沒有任何可編輯(Editable)的區域,代碼片段生成后,光標會處於這個
$end$
定義的位置。 - ID:與模板內包括在$內的占位符一一對應,只是這里不需要寫$符號而已。
- Tooltip:相應位置的具體說明。
- Defaults to:假如沒有定義Function或者Function計算不出值,就會將相應的占位符替換成這里的字符串。
- Function:這里我只找到兩種,一個是
ClassName()
,用來將占位符替換成代碼所在的類名,一個是SimplyTypeName(global::完整類名)
,用來將占位符替換成相應的類,例如,這里我們用的是SimpleTypeName(global::System.OverflowException)
。 - Editable:勾上代表該區域可編輯,生成代碼片段后,可以通過
Tab
鍵快速跳轉到相應占位符的區域,背景色為黃色,不選則代表不可編輯,如下圖所示:
- Replacement Delimiter:默認是$,你也可以使用其它的符號,被兩個此符號包裹的一串字符被認為是占位符。
修改完成后,就可以保存這個Snippet文件,注意默認會保存到MyCode Snippets對應的目錄下,因此保存完成后代碼片段管理器直接就能看到,代碼編輯器里也可以直接通過你定義的shortcut進行使用。你也可以保存到你喜歡的目錄下,再通過導入功能將其添加進來。
我們可以用記事本打開我們創建好的新Snippet文件,內容如下:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Keywords>
<Keyword>
</Keyword>
</Keywords>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<AlternativeShortcuts>
</AlternativeShortcuts>
<Title>代碼模板示例</Title>
<Author>青梅酒熟憑卿醉</Author>
<Description>本示例演示了所有內容</Description>
<HelpUrl>
</HelpUrl>
<Shortcut>tryccf</Shortcut>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>Program</ID>
<ToolTip>代碼所在類名</ToolTip>
<Default>DefaultClassName</Default>
<Function>ClassName()</Function>
</Literal>
<Literal Editable="false">
<ID>ConsoleWriteLine</ID>
<ToolTip>在控制台輸出信息</ToolTip>
<Default>Console.WriteLine</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>OverflowException</ID>
<ToolTip>溢出異常</ToolTip>
<Default>Exception</Default>
<Function>SimpleTypeName(global::System.OverflowException)</Function>
</Literal>
<Literal Editable="true">
<ID>Exception</ID>
<ToolTip>通用異常類</ToolTip>
<Default>Exception</Default>
<Function>
</Function>
</Literal>
</Declarations>
<Code Language="csharp" Delimiter="$" Kind="method body"><![CDATA[try
{
// Do something
$selected$
}
catch ($OverflowException$ ex)
{
$ConsoleWriteLine$(nameof($Program$));
$ConsoleWriteLine$(ex.StackTrace);
}
catch ($Exception$ ex)
{
$ConsoleWriteLine$(ex.Message);
}
finally
{
// Dispose
$end$
}]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>