T4 Gotcha -- fun with text transformations
A colleague of mine was having trouble with some T4 templating, which was giving apparently insane results. Figuring it out and thus fixing it took me rather longer than it ought to have, so just in case anyone else runs into the same problem...
Have some T4 template code that looks like -- after adding all the debug tracing to try and find out what was going wrong:
<# Console.WriteLine("Doing property for " + obj.Name); #> | |
<# if (obj.Property != null) #> | |
<# { #> | |
<# Console.WriteLine("obj.Property is not null"); #> | |
<# if (obj.Property == null) Console.WriteLine("obj.Property is null"); #> | |
<# PerformCalculation(obj.Property); #> | |
<# } #> |
where obj
is defined elsewhere; and you can get results like
Doing property for Address obj.Property is not null obj.Property is null System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.VisualStudio.TextTemplating32fcf58db1db4a9da645eda11cd4add4.GeneratedTextTransformation.TransformText()
which appear to defy sanity.
What is actually going on is that the intermediate code generated by the TextTransform program looks like
if (obj.Property != null) | |
#line default | |
#line hidden | |
this.Write(" "); | |
#line ... | |
{ ... |
where the leading whitespace in " <# { #>
" is being processed in such a way as to consume the if
statement.
So, despite the official MSFT brace style being Allman, T4 is actually one of those places where the K&R style is going to be much safer.
Or if that is too heretical a notion, then keep the "<#
" at the start of lines except where you explicitly want the whitespace or simply do not bracket on a per-line granularity (with the same proviso) --
<# if (obj.Property != null) | |
{ | |
Console.WriteLine("obj.Property is not null"); | |
if (obj.Property == null) Console.WriteLine("obj.Property is null"); #> | |
<# PerformCalculation(obj.Property); | |
} #> | |
... |
will help preserve your sanity.