December 15, 2006

Custom C# Code Snippets

Introduction

Code Snippets in Visual Studio 2005 [1] allow developers to create templates for common C# programming constructs, XML documentation, or any other text that one might want to quickly insert into C# code with only a couple of keystrokes. Snippets even provide the refactoring capabilities found in VS's Refactor menu. Snippets support the addition of fields and can be designed for either explicit, user-defined values or for automatic replacement, allowing a snippet to be easily customized for the particular context in which it's being used.

Visual Studio 2005 provides some out-of-the-box snippets for C# [2]. Pressing Ctrl+Space brings up the IntelliSense list of local variables, members, types and namespaces that are currently in scope relative to the position of the cursor. That same list displays all of the built-in and custom C# code snippets too.

The Benefits of Snipping

I use some of the built-in snippets from time to time, such as try, tryf, #region, #if and maybe a few others, but I believe that the real value in Code Snippets lies in the ability to create your own.

Snippet for Better Code

The quickest way to produce software is to reuse canonical code samples that work. Because there are so many different coding patterns and practices, it can be difficult to remember them all. Code Snippets facilitate the reuse of the expression of programming concepts so that they don't have to be re-analyzed each time they are needed. Of course, not all design patterns may be expressed in simple code snippets. For example, patterns that should span multiple source files cannot be developed into a single snippet; however, multiple snippets might be useful to accommodate patterns of diffusion. Although it might not be easy or effective to handle some of the more robust or complex design patterns using snippets, they are certainly helpful for the simpler, more frequent patterns.

Snippet for Consistency

It's common for personal styles and techniques to be developed or acquired over time. Snippets can be used to easily ensure that all code conforms to personal preference for style and technique. Organizational standards may be expressed and encapsulated using code snippets as well. By effectively utilizing snippets, organizations can maintain consistency across assemblies, projects and teams. Developers can ensure that trusted and proven techniques will be reused without having to remember all of the ins and outs as to why a particular snippet was designed a certain way as long as they know what it's for.

Snippet for Distribution

Snippets provide a means for encapsulating code in a manner that's easy to distribute since a snippet consists only of a single XML file. Snippets can be installed easily into Visual Studio by simply copying a .snippet file to a user's "Code Snippets\Visual C#\" directory (usually located under "My Documents\Visual Studio 2005\").

Snippet for Education

I believe that the best way to learn code is to write code. Code Snippets can encapsulate canonical representations of design patterns so they can be used as a basis for learning in the same way that code samples are used in books, websites and newsgroups to teach programmers the correct way to do something. Snippets are, in that respect, like little, bundled examples. Because of their distributable nature, snippets can be supplied easily to developers as examples of canonical, working code.

There is also the integration factor to consider. Since Visual Studio understands snippets, they can be accessed easily using IntelliSense from within the development environment itself. Visual Studio aids in the customization of snippets as well, providing a means for snippet authors to add contextual fields using replacement tokens, the replacement of which may be performed by Visual Studio or simply edited by the programmer using the snippet. This automated guidance allows developers to actually place working examples into their real code much easier than having to copy, paste and modify, or to type samples from scratch, both of which may be subject to typographical and logical errors.

Unfortunately, I haven't seen many code snippets being passed around on the web. I haven't really tried to figure out why that is, but I'll assume that it's because it just hasn't caught on yet or, more likely, it's not as useful for educational purposes as I'd like to believe.

Snippet for Sanity

Code Snippets can save you precious development time and save you from the frustrating, tedious reproduction of well-known code constructs that can make development really boring and annoying at times.

Snippets and Me

For the remainder of this blog entry I'm going to provide the source for my own personal code snippets and explain why I wrote them in the first place. Afterwards, I'll briefly explain how they can be used.

You can download all of my snippets at once or each may be downloaded separately by clicking on any of the shortcuts below.

My C# Code Snippets
ShortcutTitleSummary
event Event Member Creates the canonical event member declaration and corresponding method for invocation. EventHandler is used as the delegate. The code produced by this snippet is thread-safe.
eventc Component Event Member Creates the canonical event member declaration and corresponding method for invocation for a class that derives from System.ComponentModel.Component. EventHandler is used as the delegate. The code produced by this snippet is thread-safe.
eventg Generic Event Member Creates the canonical event member declaration and corresponding method for invocation. EventHandler<TEventArgs> is used as the delegate and TEventArgs has been tokenized. The code produced by this snippet is thread-safe.
eventcg Generic Component Event Member Creates the canonical event member declaration and corresponding method for invocation for a class that derives from System.ComponentModel.Component. EventHandler<TEventArgs> is used as the delegate and TEventArgs has been tokenized. The code produced by this snippet is thread-safe.
eventargs Custom Event Args Creates the definition for a class that inherits from EventArgs.
layout Layout Regions Creates several #region blocks for the placement of specific code elements from within the body of a class definition.
layoutd Designer Layout Regions Creates several #region blocks for the placement of specific code elements from within the body of a class definition created by a designer.



Event Members
(event, eventg, eventc, eventcg)

The standardized event design pattern [3] for .NET includes a type member using the event keyword with a corresponding protected method to raise the event. Adding an event to a type is therefore a two-step process, at least:

  • Add event member to type
  • Add method to raise event (prefixed with On)

When designing an object to be used by multiple threads it's desirable and recommended [4] to synchronize the event accessors with the method that raises the event to ensure thread-safety. This counts for even more code that, in essence, doesn't change between events:

  • Declare a synchronization object
  • Add locking mechanism to the add and remove event accessors
  • Add locking mechanism to the protected method that will raise the event

When designing types that derive from System.ComponentModel.Component, including classes that inherit from Windows Forms Controls or Web Controls, the protected Events property provides an EventHandlerList that can be used to reduce the memory footprint of the class. To use the Events property there must be some more code added:

  • Declare an object to key the event in the EventHandlerList
  • Use the Events property in the add and remove event accessors
  • Use the Events property in the method that will raise the event

My code snippets for event members handle all of the above scenarios, by default. These snippets can be invaluable to developers that frequently write custom controls or business objects that use events by reducing the amount of time it takes to adorn classes while ensuring that the code adheres to standards and has been tested.

The Different Event Member Snippets

The differences between the four event member snippets can be understood by analyzing the different suffixes on each shortcut:

The event snippet, without any suffix, is the most basic of them all. It provides the standardized, thread-safe event member paradigm in C# and adds some automatic XML documentation as well.

The c suffix indicates that a component-based event will be serialized.  It will use the Events property inherited from System.ComponentModel.Component (last three bullets above).

The g suffix indicates that the serialized event's delegate will be the generic EventHandler<TEventArgs> type. In the case of g, TEventArgs is tokenized so that its value only needs to be specified once when using the snippet. You should use this snippet if you want event arguments other than the standard EventArgs class. However, I don't provide any snippet that tokenizes the delegate itself. If your code is targeting the 1.* .NET Framework then you may want to consider writing your own snippet to replace this one.

The cg suffix is simply a combination of c and g.  (component + generics)

Layout Regions
(layout, layoutd)

I invented the layout region snippets to keep my code really neat. That's basically it. If either layout snippet is used while the cursor is within a class or struct definition, it infers the name of the type and adds a constructor with some documentation. If it's used within an interface definition then the constructor region will be serialized without a name and must be deleted manually. Here's what the layout snippet would serialize if it were to be used within a class named, Tidy:

Note: The text in red is not serialized by the layout snippets. It has been added to describe the purpose of each #region.

#region Public Properties
This region is intended for public properties, but I use it for static fields and static properties that are public as well. When I'm developing custom controls I sometimes also add nested regions to separate the different categories of properties based on the value of the CategoryAttribute. As a rule of thumb, I always group the static members before the instance members within this region.
#endregion

#region Private / Protected
All private, protected and internal instance and static fields are declared here. I also use this region for protected or internal (or both) properties. I always group properties before fields within this region.
#endregion

#region Constructors
/// <summary>
/// Constructs a new instance of the <see cref="Tidy" /> class.
/// </summary>
public Tidy(|)  (Cursor goes here automatically)
{
}
#endregion

#region Methods
All methods that do not raise or handle events are added to this region. Those methods that are prefixed with On raise events and those with signatures of specific delegates handle them (they are placed in the Event Handlers region). I try to keep all static or utility methods grouped at the top, followed by all initialization-based methods and then finally, arbitrary methods. Depending upon the class, I may also try to group public methods first.
#endregion

#region Events
This region encapsulates all events defined on the type. Since my event snippets serialize the event declaration, invocation method and supporting objects all in one place, each of those components are included here. This region is the only exception to the rule that private fields must be placed in the Private / Protected region. I layout this region based on the position of the cursor in my event snippets, where all supporting fields are grouped first, and then each event/invoker pair follows one after another.
#endregion

#region Event Handlers
All methods that handle events are added to this region. An event-handling method is one that takes the form of: void MethodName(object sender, SomeEventArgs e) { ... } Before I added the Nested region, Event Handlers was the last one in the list because Visual Studio .NET designers were actually smart enough to serialize event handlers into the last region in the code base (or that might have been a bug but I used it to my advantage). VS 2005 doesn't exhibit the same behavior so I just cut and paste designer-serialized code into the proper regions.
#endregion

#region Nested
Nested types are placed here regardless of their accessibility.
#endregion

All interface implementation regions serialized by Visual Studio appear after the last region used by the type.



Not all regions are used in every type that I define. For instance, I usually remove the Nested region immediately after I use the layout snippet. For interfaces, I remove everything except Public Properties, Methods and Events. For stucts I usually remove everything below Methods.  If I predict, for any type, that a particular region will never be used then I'll remove it immediately.

I do not distinguish between members marked as unsafe, fixed, abstract, virtual, override or sealed. However, extern methods are placed in the Methods region below every other method or within a nested region if there are many of them.

When overriding derived methods that raise events (methods beginning with an On prefix), I place them in the Event Handlers region since that is usually the purpose for overriding them in the first place.

The layoutd alternative provides one subtle difference and one obvious difference. The obvious difference is that it serializes a call to InitializeComponent(); within the constructor. When I use layoutd I select the existing constructor that was serialized by the designer and then execute the snippet so that it's completely replaced.  The subtle difference that layoutd provides is that the cursor is no longer placed where the constructor parameters could be entered, but is instead placed within the Private / Protected region on an empty line.

Since I invented the layout snippets I've made it a habit when I open up source code to immediately right-mouse click and select Outlining → Collapse To Definitions from the context menu, making it much easier to navigate my code. This allows me to visualize where code elements are placed instead of blindly using the drop-down lists at the top of the document, which I avoid completely.

Using Snippets

I learned how to write snippets using the documentation on MSDN [1] and I found it to be quite easy, so I'm not going to elaborate here. I'll just provide a synopsis to get snippet-newbs started.

Create a .snippet File

I suggest that you download one of my files as a starting template. You may find the layout template to be useful at first because it's fairly barren. This way you can get an idea about some of the structural xml elements that are supported without the bloat of some of the more advanced concepts such as replaceable tokens. For a more advanced example see eventcg.

I recommend naming the file with the same name as the shortcut that will execute it, with ".snippet" appended to the end (the extension is required by Visual Studio but the name portion seems to be completely ignored). Specify the shortcut in the <Shortcut> element under the <Header> element within the snippet's XML.

Save the snippet file to your "Code Snippets\Visual C#\" folder usually located under "My Documents\Visual Studio 2005\". You don't have to restart Visual Studio. As a matter of fact, you don't even have to close and reopen the current document. Simply save your snippet, go back into VS and press Ctrl+Space to open the IntelliSense list from within a C# code file. Start typing the shortcut for your snippet and you should see it in the list. Pretty cool ;)

Types of Snippets

There are three ways that snippets can be typed: SurroundsWith, Expansion and Refactoring. A custom snippet may be any combination of the first two but not Refactoring. The type of a snippet must be specified by including one <SnippetType> element for each type. They must be placed within the <SnippetTypes> element, which is located in the snippet's <Header> element.

Executing Snippets

Expansion snippets are executed easily by typing their shortcut and pressing tab.

SurroundsWith may be executed using a special key combination (CTRL+K, CTRL+S), by selecting the Edit → IntelliSense → Surround With menu item, or from the context menu by selecting Surround With.

Refactoring snippets are executed by selecting the corresponding menu item from the Refactor menu or context menu. Custom snippets do not support this type.

Using Fields

To fill out a snippet's fields when it's being used you can continue to press tab after the snippet is started, and for each green box that receives focus when you press tab you can type in a new value.  Pressing tab repeatedly will eventually cycle through all of the replaceable tokens in the snippet and start over again from the first token. Note, however, that only the first appearance of a field within the snippet is editable. The remaining instances will take on the same value entered in the first instance.  When you are finished customizing the snippet, make sure that the cursor is within one of the green areas and press Enter or Esc once.

Snippets For Refactoring

Browse to your "Program Files\Microsoft Visual Studio 8\VC#\Snippets\language id\Refactoring" directory and you'll find the snippets used to perform the refactoring techniques in the Refactor menu. Notice that these snippets have a <SnippetType> element with a value of Refactoring, which cannot be specified in custom snippets. If you're going to try modifying these snippets then don't forget to back them up first, otherwise you can take a look at [5] if you mess them up.

Modifying these snippets can be quite useful. For instance, have you noticed that when Visual Studio stubs out an interface implementation, whether implicit or explicit, all methods contain a single line of code that throws a new Exception with the text, "The method or operation is not implemented."? Great, but why not just throw NotImplementedException instead? Well, you can easily adjust MethodStub.snippet to do that by simply replacing global::System.Exception with global::System.NotImplementedException for the Exception field, which uses the SimpleTypeName function.

--
References

[1] Visual C# Application Development, Code Snippets
http://msdn2.microsoft.com/en-gb/library/f7d3wz0k(VS.80).aspx

[2] Visual C# Application Development, Default Code Snippets
http://msdn2.microsoft.com/en-gb/library/z41h7fat(VS.80).aspx

[3] .NET Framework Developer's Guide, Event Design
http://msdn2.microsoft.com/en-us/library/ms229011.aspx

[4] J. Skeet, Delegates and events
http://www.yoda.arachsys.com/csharp/events.html

[5] Visual C# Language Concepts, How to: Restore C# Refactoring Snippets
http://msdn2.microsoft.com/en-gb/library/ms236401(VS.80).aspx

As always, I'd love to hear from anyone that has something to say about this post.  Drop me a comment.

Add comment