Custom VS Snippets

The 'copy-paste' task of developers has to be automatized. It is done by continuous improvement of languages, compilers, design patterns, libraries, packages, components, etc.

Having code templates is a bit of a different story. I have been using R# templates for a couple of years, and one can get really used to it.

Recently I have decided to plainly use Visual Studio, without the R#. One challenge I have is to move all my templates to VS snippets. I tend to use 6 snippets the most often:

  • Argument validation

  • Log informational message

  • Log error message

  • Create a test method

  • Create test setup method

  • Create test tear down method

Let's start with argument validation. I use this snippet the validate that a dependency is not null. I usually use it to validate injected constructor dependencies.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
  <Header>
    <Title>ArgumentValidation</Title>
    <Shortcut>argval</Shortcut>
    <Description>Validates your input arguments</Description>
    <Author>Laszlo</Author>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Imports>
      <Import>
        <Namespace>System</Namespace>
      </Import>
    </Imports>
    <Declarations>
      <Literal>
        <ID>dependency</ID>
        <ToolTip>Name of the parameter to be validated</ToolTip>
        <Default>param</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp" Kind="method body">
      <![CDATA[_$dependency$ = $dependency$ ?? throw new ArgumentNullException(nameof($dependency$));
      ]]>
    </Code>
  </Snippet>
</CodeSnippet>
</CodeSnippets>

The first part of the snippet is the header. It defines the name, the shortcut which is the one to be typed/offered by VS intellisense. Using the shortcut + TAB + TAB will trigger our snippet. This snippet is typed 'Expansion', so will insert the snippets code at the current place of the cursor.

The next part of the snippet is imports. Imports define a list a of namespaces to be used. Here I will add a using System; so I can use the short name of ArgumentNullException type. We could also add assembly references which I tend to omit. Assembly references are still best to be added manually, so developer is well aware of his/her intent.

Declarations can declare literals or objects, used to identify a replacement for a piece of code. I define one literal $dependency$, that is going to be the name of an input parameter to be validated.

The most interesting part is the code, where in a CDATA we can write our snippet's code. In this case the above code uses the dependency literal that is replaced by the user. As an example, using the following code in a ctr:

public class SampleClass
{
  private readonly IMyDependency _dep;
  public SampleClass(IMyDependency dep)
  {
  }
}

We would like to validate dep not to be null. Typing argval + TAB + TAB while are cursor is at the bode of our ctr. will insert the snippet and let us type the name of the parameter to be validated $dependency$. After using the snippet our code will look like this:

using System;
...
public class SampleClass
{
  private readonly IMyDependency _dep;
  public SampleClass(IMyDependency dep)
  {
    _dep = dep ?? throw new ArgumentNullException(nameof(dep));
  }
}

argument validation

At this point, I will only briefly show the other snippets I use.

LogInfo and LogError usually using some ILogger interface. Having an Info and Error methods to log the message, also having an IsInfoLoggable() and IsErrorLoggable() the check if we shall even emit log message. (By checking we can improve performance by not logging message and by reducing the pressure on GC for not collecting strings we would otherwise create but actually not log). In this case I use $logger$ and $message$ literals.

<Code Language="CSharp" Kind="method body">
<![CDATA[
if($logger$.IsInfoLoggable())
{
    $logger$.Info($$"$message$");
}
]]>
</Code>

I only share the code node of the snippet here. I log error is very similar, but using Error method and an '' literal as well.

The following snippets are used for creating methods in unit tests. Either we use NUnit or MSTest or other frameworks, we would create similar methods, but with different attributes applied on them. (ie. a unit test method has [Test] attribute in NUnit, while [TestMethod] in MS Test.

TestMethod using the AAA naming convention:

<Code Language="CSharp" Kind="method decl">
<![CDATA[
[TestMethod]
public void Given$input$_When$action$_Returns$result$()
{
    Assert.Fail();$end$
}
]]>
</Code>

Note the attribute Kind here is changed from method body to method declaration. This helps VS to tell where the snippet is to be applied. Previous snippets are to be applied inside a method body, while these are method declarations. The '' is a special literal, it tells VS where to place the cursor after the snippet has been applied. One part where R# templates are better is that we can define literals with more details. For example R# would allow to define a list of possible values (True, False, Null, NotNull, Exception) for that are offered by the intellisense.

Similarly we can have a setup and tier down method run before and after our test method:

<Code Language="CSharp" Kind="method decl">
<![CDATA[
[TestInitialize]
public void Initialize()
{
    $end$
}
]]>
</Code>

Tear down:

<Code Language="CSharp" Kind="method decl">
<![CDATA[
[TestCleanup]
public void Cleanup()
{
    $end$
}
]]>
</Code>

Final thoughts: the full Snippet reference is available here. There are couple of functions that can be used in snippets, for example to use a selected text, or the name of a type of the context, though the above snippets do not harness them.