Tuesday, June 14, 2011

Coding with code snippets

My main coding tool is Visual Studio. That product has support for what they call "Code Snippets". Code Snippets are typically small chunks of code that you use frequently, that you can easily insert in to your code. It's like clip-board on steroids.


VS ships with a number of code snippets. They typically live here

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC#\Snippets\1033\Visual C#.



Code snippets are straight XML files with a .snippet extension. Because that extension is registered with VS, clicking on such a file will open it up in VS. Notepad works fine too. We'll look at one of the shipping snippets, and use it for the bases of our own custom snippet. We'll look at prop.snippet:


<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Titlegt;prop</Title>
<Shortcut>prop</Shortcut>
<Description>Code snippet for an automatically implemented property
Language Version: C# 3.0 or higher</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[public $type$ $property$ { get; set; }$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


A couple of things to note here. The shortcut is the "keyword" you can type in order to insert the code snippet in to your code. Open a C# file, and within a class, where you would normally insert a property, type prop, then hit the tab key twice. "prop" expands out to "public int MyPropery { get; set; }" Very cool. 28 keystrokes saved. Note that there are two fields that are "highlighted". Tabbing toggles between them. There is a replacement functionality that is available when you first insert a snippet, and the items that are "highlighted" are items that can be replaced. In this case, the author thinks that you'll probably want to replace the property type and the property name with your own, so you can tab from one to another and type in the replacement. In the code snippet, those replacements are in the Declaration section. Here is one:


<id>type</id>
<tooltip>Property type</tooltip>
<default>int</default>


This explains itself. In the code section, all instances of "$type$" will be replaced with "int", and be highlighted for modification. In this simple snippet, there is only one instance of each replacement, but in the more complex one we'll write, the same replacement will appear multiple times, and changing one with change all.

The code section looks like this:

<code language="csharp"><!--[CDATA[public $type$ $property$ { get; set; }$end$]]--></code>


The "$end$" is unknown to me, but perhaps is a built-in replacement for line-feed.

The first useful snippet I'll create is the the Assert that I use on non-null function arguments. I used code contracts once, but to fully take advantage of them you need to use a VS extension. Not an option for us VS Express hackers, so I've dropped back to using:

Debug.Assert(null != parameter);


Here is my implementation:


<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>assertnotnull</Title>
<Shortcut>asnot</Shortcut>
<Description>Code snippet to validate not-null parameters</Description>
<Author>pizza-code</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>parameter</ID>
<ToolTip>non-null Parameter</ToolTip>
<Default>argument</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[Debug.Assert(null != $parameter$);$end$]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


Save this file as "AssertNotNull.snippet" to your a "Code Snippets" directory in your Documents folder. Mine is:

C:\Users\codecore\Documents\Code Snippets\AssertNotNull.snippet


If notepad is your editor, additional work may be required to remove the ".txt" extension.
Now that you've written your new code snippet, or copied mine, how do you let VS know about it?
Menu->Tools->Code Snippet Manager

The "Code Snippets Manager" dialog contains entries for the code snippet locations that it knows about. If Language is "Visual C#", I see a "Refactoring" and a "Visual C#" entry. Use the "Add" button, and find the directory that you saved your new custom snippet file in. You have import individual snippet files directly using the "import" button. VS now knows about your snippets. The directory of snippets are loaded when VS starts, or when you add the directory to it's knowledge. Adding new snippet files to your snippet directory will not be known to VS. A VS restart, or remove-add will be required to pick-up the new snippets.


Should you be running an edition of VS that supports extension, there is a free snippet tool available, mentioned by Robert Greene in this excellent Channel 9 video: http://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Visual-Studio-Toolbox-Creating-and-Using-Code-Snippets


Here are a couple more of my favorite snippets:
NotifyPropery.snippet aka "propf"


<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propf</Title>
<Shortcut>propf</Shortcut>
<Description>Code snippet to implemented INotifyPropertyChanged property</Description>
<Author>pizza-code</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>string</Default>
</Literal>
<Literal>
<ID>back</ID>
<ToolTip>Backing Property name</ToolTip>
<Default>back</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Public Property name</ToolTip>
<Default>Property</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[
protected $type$ $back$;
public $type$ $property$ {
get { return this.$back$; }
private set {
if (value != this.$back$) {
this.$back$ = value;
this.FirePropertyChanged("$property$");
}
}
}$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>


Finally, here is FirePropertyChanged.snippet aka "fire"


<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>fire</Title>
<Shortcut>fire</Shortcut>
<Description>Code snippet for implementing INotifyPropertyChanged interface</Description>
<Author>pizza-code</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Code Language="csharp"><![CDATA[public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChanged(string propertyName) {
if (null != this.PropertyChanged) this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>