Escaping Generics with T4 Templates

Posted by Gavin Stevens on Geeks with Blogs See other posts from Geeks with Blogs or by Gavin Stevens
Published on Sat, 13 Mar 2010 22:13:39 GMT Indexed on 2010/03/13 22:35 UTC
Read the original article Hit count: 637

Filed under:

I've been doing some work with T4 templates lately and ran into an issue which I couldn't find an answer to anywhere.  I finally figured it out, so I thought I'd share the solution.

I was trying to generate a code class with a T4 template which used generics

The end result a method like:

public IEnumerator GetEnumerator()
            {
                return new TableEnumerator<Table>(_page);
            }

the related section of the T4 template looks like this:

 public IEnumerator GetEnumerator()
            {
                return new TableEnumerator<#=renderClass.Name#>(_page);
            }

But this of course is missing the Generic Syntax for < > which T4 complains about because < > are reserved.

using syntax like <#<#><#=renderClass.Name#><#=<#> won't work becasue the TextTransformation engine chokes on them.  resulting in : Error 2 The number of opening brackets ('<#') does not match the number of closing brackets ('#>') 

even trying to escape the characters won't work: <#\<#><#=renderClass.Name#><#\<#> this results in:

Error 4 A Statement cannot appear after the first class feature in the template. Only boilerplate, expressions and other class features are allowed after the first class feature block. 

The final solution delcares a few strings to represent the literals like this:

<#+
   void RenderCollectionEnumerator(RenderCollection renderClass)
 {  
  string open = "<";
  string close =">";
#>
   public partial class <#=renderClass.Name#> : IEnumerable
        {
            private readonly PageBase _page;
            public <#=renderClass.Name#>(PageBase page)
            {
                _page = page;
            }

            public IEnumerator GetEnumerator()
            {
                return new TableEnumerator<#=open#><#=renderClass.Name#><#=close#>(_page);
            }
        }
<#+
 } 
#>

This works, and everyone is happy, resulting in an automatically generated class enumerator, complete with generics!

Hopefully this will save someone some time :)

© Geeks with Blogs or respective owner