Monday, March 03, 2008

StringProviders vs TextCommands

The problem
Recently asked on the DevExpress CodeRush Forum was a question relating to why a given user-created template did not appear to work.

The template in question was one designed to create a local variable of the same type as it's parent functions return type.

The template shown was:
-------------------------------------------------------------
«ReturnType» «Caret»«Field(«?FormatLocalName(«ReturnType»)»)»«BlockAnchor» = new «ReturnType»(«Field»);
-------------------------------------------------------------

The poster was hoping that this would produce...
-------------------------------------------------------------
List<Order> listOrder = new List<Order>();
-------------------------------------------------------------
...when the template was activated from within a function which returned a generic list of some type called 'Order'.

On the face of it, this is not an unreasonable expectation.

Why doesn't this work? 
To explain what is happening here it's important to understand 'ReturnType' is not a StringProvider. It is a TextCommand.

"So what....?" I hear you say.

Well TextCommands are like a 'void proc' in C# or a 'Sub' in VB.Net. Which is to say that they are functions which don't return a value and therefore they cannot really be passed to other StringProviders or TextCommands.

String providers on the other hand do support returning values (indeed that is their purpose. ie provide a string :) )

That begs the question: Why is ReturnType a TextCommand?
Well to tell you the truth I haven't a clue :) I do know however, that thanks to the wonder that is the DXCore, it's really easy to create a new StringProvider which adds exactly the functionality that the original poster wanted.

Create a StringProvider
The steps to create a valid StringProvider are quite simple.

A StringProvider lives in a Standard DXCore plugin Project. You need to create such a project and add a StringProvider Component to it's design surface.

Note: The StringProvider normally sits in the toolbox on the left hand side of visual studio. If it's not there, right-click and select 'Choose items'. This will allow you to select assemblies and, within them, components and controls which you can add to the toolbox. The StringProvider component is located in the 'DevExpress.CodeRush.Extensions.dll' assembly which is held in the GAC and can be referenced from the 'C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin' directory (by default).

Once the StringProvider is on your design surface, you should set a few of it's properties.

Name = "ReturnType"
Description = "Returns a string representing the name of the type returned by the activeMethod"
DisplayName = "ReturnType"
ProviderName = "ReturnType"

Finally handle the StringProvider's GetString Event with the following code:
-------------------------------------------------------------
ea.Value = CodeRush.Source.ActiveMethod.GetTypeName
-------------------------------------------------------------
Feel free to add a semi-colon if you're of the C# persuasion.

Use your new StringProvider
Once you compile your new StringProvider plugin, you should be able to access it like any other.

So instead of...
-------------------------------------------------------------
«ReturnType» «Caret»«Field(«?FormatLocalName(«ReturnType»)»)»«BlockAnchor» = new «ReturnType»(«Field»);
-------------------------------------------------------------
...we now have ...
-------------------------------------------------------------
«?ReturnType» «Caret»«Field(«?FormatLocalName(«?ReturnType»)»)»«BlockAnchor» = new «?ReturnType»(«Field»);
-------------------------------------------------------------

And we're done :)

Questions ?


2 comments:

Andre said...

Thanks for that! It's great to see some information on the web every now and again that is actually useful.

Rory said...

You're quite welcome.. I'm very glad to have been of help :)