Rory Becker - DevExpress CodeRush Blog

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.

Published Jan 19 2011, 02:47 PM by
Bookmark and Share

Comments

Przemyslaw Wlodarczak

instead of creating new mnemonic for virtual methods, better to use some convention. e.g. currently CodeRush uses "-" for abstract members. this way "c-" template creates abstract class, "ms-" creates abstract method returning string, "ps-" creates abstract string property. I propose using "=" for virtual members. This way convention can be applied to properties as well. "ms=" would create virtual method returning string, whereas "pi=" would create virtual string property. Simple, consistent and does not require to learn new mnemonic for "virtual methods" and another one for "virtual properties" (and as you pointed out, there are troubles to find good mnemonic that is still free to use). One convention is easier to learn than two new mnemonics IMHO.

January 21, 2011 5:34 AM

Przemyslaw Wlodarczak

Turms out, there are actually 5 types of templates that can be decorated with virtual keyword: m, p, r, w and ev. I filled suggestion in support center regarding this: www.devexpress.com/.../S136311.aspx

January 21, 2011 8:14 AM

Rory Becker - DevExpress

Sounds like a great suggestion

January 21, 2011 8:18 AM
LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2017 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners