The problem
While C# compiler provides a decent level of generic parameter type inference there’s a bunch of scenarios where it does not work, and you have to specify the generic parameters explicitly.
One such case is when you invoke a generic method inline, and the return type is the generic type parameter.
In other words, the following scenario:
In this case the compiler won’t infer the generic parameter of GenericMethod
and you have to specify it explicitly.
As helpful as Resharper often is, it also doesn’t currently provide any help (other than placing the cursor at the appropriate location) and you have to specify the type parameter yourself.
Oh the typing!
I’m quite sensitive to friction in my development work, and I found this limitation quite annoying. Especially that the pattern is used quite often.
Specifically the excellent NSubstitute mocking framework is using it for creation of mocks via
Substitute.For<IMyTypeToMock>();
method.
If I wanted to use NSubstitute to provide the argument for my GenericMethod
I’d have to do quite a lot of typing:
type Su
or few more characters to position completion on the Substitute
class.
Press Enter
.
Type .
and assuming the right overload of For
is selected press Enter
again (or press arrow to pick the right overload before that).
Finally, type enough of the expected type’s name for completion to select it, and press Enter
to finish the statement.
It may not look like much but if you’re writing a lot of tests those things add up. It ends up being just enough repetitive typing to break the flow of thoughts and make you concentrate on the irrelevant mechanics (how to create a mock for IFoo
) rather than what your test is supposed to be doing (verifying behavior of UsesIFoo
method when a non-null arg
is passed).
Resharper to the rescue
While there’s no easy way to solve the general problem, we can use Resharper to help us solve it in this specific case with NSubstitute (or any other API, I’m using NSubstitute as an example here).
For that, we’ll write a Smart Template.
How to: writing a Smart Template
Go to Resharper menu, and pick Templates Explorer…
Make sure you’re on the Live Templates tab, and click New Template.
For Shortcut select whatever you want to appear in your code completion for the template, for example NSub
.
Select the template should be allowed in C# where expression is allowed.
Check Reformat and Shorten qualified references checkboxes and proceed to specifying the template itself, as follows:
NSubstitute.Substitute.For<$type$>()
The $type$
is a template variable, and the grid on the right hand side allows us to associate a macro with it. That’s where the magic happens.
Pick Change macro… and select Guess type expected at this point.
After you’ve done all of that, make sure you save the template.
Result
Now your template will be available in the code completion.
All it takes to get to the end result now is to type ns
, Enter
, Enter
.
The main benefit though is not the keystrokes you save, but the fact there’s almost no friction to the process, so you don’t get distracted from thinking about logic of your test.
Comments
Thank you for inspiring article. I created few templates for CodeRush https://github.com/rarous/CodeRushTemplates
Thanks Krzysztof,
Another good one that I like to use is:
test ->
[TestMethod] // adjust for your preferred unit testing framework
public void $Method$_$Behaviour$()
{
$end$
}
Yeah, I’ve got that one too 🙂 It’s kind of the obvious candidate.
Krzysztof, your shortcut is good however given you typed this implies you are not aware of Resharpers (very handy) ‘Type Name Completion’ shortcut.
>Finally, type enough of the expected type’s name for completion to select it, and press Enter to finish the statement.
An example, when you have:
IFoo foo = Substitute.For
when the cursor is placed between the press Ctrl-Alt-Space and the type will be inserted. This is just one handy application of this invaluable shortcut.
http://www.jetbrains.com/resharper/webhelp/Coding_Assistance__Code_Completion__Type_Name.html
You’re right, it would indeed speed things up a little bit in this case.
Still, you’d have to type the Substitute.For() yourself
yes just thought i would mention it in case you are not using this shortcut, it is so handy!
consider the situation (purely as an example) where you have a method or ctor and you want to call it with args in scope:
Foo1 foo1;
Foo2 foo2;
Foo3 foo3;
DoMegaStuff(…)
//the line above just press Ctrl-Alt-Space x3 ! (or mash the keyboard erratically until its done like i do :))
public void DoMegaStuff(Foo1 f1, Foo2 f2, Foo3 f3)
{
}