CodeRush Template – Creating Virtual Methods

CodeRush provides many templates for lots of different purposes. Of course you can’t cover every eventuality out of the box. So instead we built a system which allows you to build a solution of your own when you need to.

Recently I was asked if there was a quick way to create a public virtual method.

I did a quick search and discovered that there did not appear to be any pre-built in template that did this.

However, as I’ve said before, building this sort of thing is pretty easy. So I decided to prove it and do the leg work to build my own.

There are 2 parts to this: Naming and Implementation.

Naming

Well it turns out the naming is the hard part.

It’s always good to have your templates named something which suggests the purpose of the template. Failing that, it should be closely related. ie There should be some logical link.

Additionally it’s great if you can use as few keys as possible. Short of using mind control, and therefore zero keys, ideally we’ll settle for one… But which one?

To this end I asked myself what the appropriate name for a template that produced virtual methods would be…

  • V – Already used for Variables
  • I  - Already used for Interfaces
  • R - Already used for Readonly properties
  • T - Already used for Types
  • U - Unused
  • A - Already used for auto-Implemented properties.
  • L – Unused

Well that didn’t leave much of a choice. U or L.

I chose L.

Implementation

Next up we need to create 2 templates which will provide us with the output we need.

The original request was to produce a template which would output a public virtual method. The example given showed a void proc, but I figured it would be better to also provide the ability to produce methods that returned various types like our other dynamic templates.

So I decided to base my templates on the m<space> and m?Type?<space> templates. This allows us to pass in any of the usual type params, or miss that out entirely and just emit a void proc as per the original example.

If you’re unfamiliar with creating templates, or would like a quick refresher, then it’s probably worth reviewing my previous post on Template Creation Basics

The Templates

I created the following templates:

Name: l?Type?
Context: Editor\Code\InClass
Expansion:
-------------------------------------------------------------
public virtual «:#MethodSignature#»«:#MethodBody#»
-------------------------------------------------------------


...then a second template...
Name: l
Context: Editor\Code\InClass
Expansion:
-------------------------------------------------------------
«Set(Type,void)»«:l?Type?»
-------------------------------------------------------------

Note: The contexts indicated above are a little simplistic. In reality, we should base the context from the m?Type? template.
This would be something like: ((InClass or InStruct) and OnEmptyLine) but not (InComment or InMethod or InPreprocessorDirective or InProperty or InString)

How does this work?

In this section I'm going to explain a little of the detail about how these templates work with one another. If you don’t care about this, then feel free to skip ahead. There’s nothing vital here, but for those who are interested in creating their own templates, deconstructing an existing set can be useful.

Let’s start with the l?Type? template which you added above:

This template emits the phrase “public virtual “ and then defers to 2 other templates (#MethodSignature# and #MethodBody#) for the rest of it’s functionality.

Note: Templates whose names are surrounded by # (pound signs or hash marks depending on your point of view) are called system templates. This is not because the have special access to system functionality or anything. Instead it’s because that naming convention is judged to make them unlikely to be called by a user directly and therefore are assumed to be in use solely by other templates (ie the system).

If you look, you’ll find that each of these has their own expansions.

#MethodSignature#

Template#MethodSignature#

#MethodBody#

Template#MethodBody#

Additionally #MethodSignature# also calls a level deeper into the #MethodParameters# template...

#MethodParameters#

Template#MethodParameters#

This style of aliasing, is like calling a method. It allows you to extract a piece of a template and reuse it from as many places as you like. In this case we get to reuse functionality from templates that the DevTeam already created.

If we expand  these aliases in the same way that CodeRush would, you can see what we would have had to type without this facility.

TemplateLTypeAliasesExpanded

So how does this work?

Well this template does 6 things

  1. The literal phrase “public virtual” is emitted into the editor.
  2. The «?Get(Type)» StringProvider emits a reference to the Type passed in the trigger string. (String,int32, Dataset etc)
  3. The MethodName is wrapped in a «Field» in order to suggest a suitable edit point.
  4. This field is wrapped in  «Caret» and «BlockAnchor» pair indicating that Studio should select this text.
  5. A further «Field» is created to allow the entry of any method parameters.
  6. A method body stub is emitted. This contains a «FinalTarget» TextCommand within it represents the position to move the caret to when both fields have been entered.

In the case of the 2nd template, we use «Set(Type,void)» in order to pre-set the type to void (ie no return type) and the call the 1st template via «:l?Type?». This passes the void type to the 1st template causing it to expand a method stub which returns no value.

Note: To add even more functionality, you could create duplicate versions of these templates that omit the “#MethodBody#” aliases and the “public” keyword, making said duplicates suitable for use inside of interfaces. Of course the contexts of these duplicates should also be altered to only work inside of interfaces, but I’m sure you can see how quickly this could be achieved.

Usage

Well the usage of the template is quite simple. Position the caret somewhere sensible within a class or structure…

Type ls<space>

… and you will be rewarded with the stub of a public virtual method that returns a string. Alter it’s name and hit enter. Your caret jumps within the parenthesis ready for you to expand templates to.

Additionally you can use…

l<space>

…to omit a return type and have the system emit a void proc instead.

Conclusion

As you can see, there’s not much to each of the parts involved in these templates. The power instead, is in the flexibility of each part, and the combinations in which they can be used. And so we have gone from feature request to fully developed feature in no more that 15 minutes.

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.
No Comments

Please login or register to post comments.