1. Introduction

Le Template T4 est une technologie de génération de code, existant depuis Visual Studio 2005. Développée par Microsoft, cette technologie peut servir dans de nombreuses situations.

Le fonctionnement est simple : on écrit un Template (code) qui permettra de générer des fichiers, du code... Cette technologie est très flexible et on pourra l'adapter à tous les problèmes.

Enfin, sachez qu'aucune installation supplémentaire n'est requise si vous disposez de Visual Studio 2008 ou 2010.

2. Outils

Comme nous l'avons vu dans l'introduction, aucun outil supplémentaire n'est nécessaire à l'utilisation des Templates T4. Néanmoins, l'intégration par défaut laisse à désirer :

  • pas de coloration syntaxique ;
  • pas d'autocomplétion.

Je vais donc vous présenter une liste d'outils qui vont nous permettre de travailler dans de meilleures conditions. Je n'ai pas la prétention de connaître tous les outils existants. Si vous pensez repérer un manque, faites-le moi parvenir et je me ferai une joie de l'intégrer à cet article.

2.1. T4 Toolbox

La T4 Toolbox est un peu le couteau suisse du Template T4 ! Elle apporte de nombreuses fonctionnalités qui pourront vous aider à la création de Templates T4 avancés. Une de ces fonctionnalités primordiales est à mon sens la possibilité de générer plusieurs fichiers depuis un seul Template T4.

Vous pouvez télécharger la T4 Toolbox ici : http://t4toolbox.codeplex.com/T4 Toolbox.

2.2. Tangible T4 Editor

Tangible T4 Editor est un éditeur pour Templates T4. Il apporte principalement la coloration syntaxique, mais aussi l'autocomplétion. Il fournit aussi une galerie de Templates, très utile pour éviter de réinventer la roue.

Attention : Tangible T4 Editor est un logiciel payant. Une version gratuite est proposée, mais vous devrez faire face à quelques limitations : autocomplétion limitée à certaines assemblies, modélisation UML limitée. Pour le téléchargement, ça se passe ici : Tangible T4 Editor.

Image non disponible

2.3. Visual T4

Visual T4 est un plugin pour Visual Studio qui apporte la coloration syntaxique mais aussi l'autocomplétion. À la différence de Tangible T4 Editor, il est entièrement gratuit. Je vous conseille de comparer les deux et de prendre celui sur lequel vous êtes le plus à l'aise.

Le téléchargement se passe ici : Visual T4.

3. Les Templates T4 en détails

Avant toute chose, nous allons nous intéresser à la syntaxe des Templates T4. Nous partirons sur un cas pratique par la suite, qui nous permettra d'assimiler ces informations.

3.1. Syntaxe

Les Templates T4 disposent d'une syntaxe qui leur est propre. Cette syntaxe ressemble à celle de l'ASP, et est donc facile à assimiler.

La première chose à savoir est que tout texte saisi hors balise se retrouvera au sein du fichier de sortie. Prenons l'exemple du Template T4 suivant :

 
Sélectionnez

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ output extension=".txt" encoding="UTF8" #>
Hello World !

Le résultat sera un simple fichier texte comprenant "Hello World !".

Un bloc de code s'insère de cette manière :

 
Sélectionnez

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ output extension=".txt" encoding="UTF8" #>
<#
String message = "Hello World !";
#>

Pour afficher une variable ou du texte issu d'un traitement :

 
Sélectionnez

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ output extension=".txt" encoding="UTF8" #>
<#
String message = "Hello World !";
#>
<#= message #>

Il existe un dernier type de bloc dans les Templates T4 : les class feature blocks. Ces blocs permettent de déclarer des classes et des méthodes utilisables dans votre Template T4. Ces blocs doivent toujours être déclarés en fin de votre Template T4 et s'utilisent de la manière suivante :

 
Sélectionnez

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ output extension=".txt" encoding="UTF8" #>

<#= ToUpper("Hello World !") #>

<#+

public string ToUpper(String message)
{
	return message.ToUpper();
}
#>

Pour faire un petit résumé, voici les différentes balises des Templates T4 :

  • <#@ #> : directive ;
  • <# #> : bloc de code ;
  • <#= #> : affichage de texte depuis du code ;
  • <#+ #> : class feature blocks.

3.2. Les directives

Les directives sont des informations à placer obligatoirement au début de votre Template T4. Elles permettent de spécifier le comportement de celui-ci. Elles se composent toutes de la même syntaxe :

Syntaxe directives templates T4
Sélectionnez

<#@ DirectiveName [Attribute = "Value"] #>

3.2.1. Template

La directive Template est la directive principale d'un Template T4. Elle va permettre de spécifier les caractéristiques générales de notre Template T4 :

  • Language [string] : spécifie le langage du Template T4 (VB, C#) ;
  • Debug [bool] : active ou désactive le débogage sur le Template ;
  • HostSpecific [bool] : donne accès ou non à l'objet Host, fournissant un ensemble d'informations ;
  • Inherits [string] : spécifie la classe de génération dont hérite le Template T4. Cet attribut est facultatif et a pour valeur par défaut TextTransformation.

3.2.2. Output

Quand on utilise un Template T4, le code généré va se retrouver dans un fichier de sortie. Ce fichier porte le même nom que celui du Template T4. Pour le visionner, il suffit de déplier le fichier .tt dans l'explorateur de solutions.

Nous avons aussi la possibilité de spécifier l'extension du fichier de sortie. Pour cela, il suffit de modifier cette ligne :

 
Sélectionnez

<#@ output extension=".txt" #>

Un Template T4 ne génère par défaut qu'un unique fichier de sortie. Un article à venir décrira comment générer plusieurs fichiers de sortie.

Nous allons aussi pouvoir spécifier l'encodage du fichier de sortie. Pour cela, on va ajouter l'attribut encoding :

 
Sélectionnez

<#@ output extension=".txt" encoding="UTF8" #>

3.2.3. Assembly

Lorsque l'on crée un Template T4, celui-ci ne possède pas les références de notre projet. Nous allons donc, dans certains cas, lui ajouter des références. Pour cela, nous disposons de la directive Assembly :

 
Sélectionnez

<#@ assembly name="System.Data" #>

On peut noter que certaines "assemblies" sont incluses par défaut dans un Template T4 :

  • System ;
  • Microsoft.VisualStudio.TextTemplating.VSHost ;
  • Microsoft.VisualStudio.TextTemplating.dll ;
  • mscorlib.

3.2.4. Import

Dans notre Template T4, nous ne pouvons pas utiliser les usings. Nous allons donc utiliser la directive Import, qui répond à la même problématique. Celle-ci s'utilise de cette manière :

 
Sélectionnez

<#@ import namespace="System.Data.SqlClient" #>

3.2.5. Include

Au sein de notre Template T4, nous pouvons aussi inclure d'autres Templates T4, grâce à la directive Include. Les chemins peuvent être relatifs ou absolus :

 
Sélectionnez

<#@ include file="c:\Projects\T4\include1.tt" #>
<#@ include file="..\T4\include1.tt" #>

3.3. Exécution

Maintenant que nous avons créé notre Template T4, nous allons l'exécuter pour lancer la génération de notre fichier de sortie. Plusieurs options s'offrent à nous :

  • sauvegarder le fichier .tt : cette action lance automatiquement l'exécution du Template T4 ;
  • clic droit sur notre fichier .tt : exécuter un outil personnalisé ;
  • utiliser le bouton spécifique dans l'explorateur de solution (lance l'exécution de tous les Templates T4) : Image non disponible.

4. Un peu de pratique

Maintenant que nous avons vu la théorie, nous allons passer à la pratique. Nous allons créer un Template T4 qui va parcourir un dossier contenant des classes, et pour chacune d'elles, générer une propriété dans notre fichier de sortie. L'intérêt du Template en lui-même est limité, mais il nous permettra d'appréhender la création d'un Template T4.

4.1. Création de la solution

Notre solution va être simple : un projet de type "bibliothèque de classes", comprenant un dossier "classes" et notre Template T4 :

Templates T4 par Kevin Perriat

4.2. Création du Template T4

Dans un premier temps, nous allons modifier le type de sortie de notre Template T4 en fichier .cs mais aussi importer le namespace System.IO :

 
Sélectionnez

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>

Une fois cette étape réalisée, nous allons créer des variables utiles au fonctionnement de notre Template T4 :

 
Sélectionnez

string NameClass = "ClassT4"; //nom de la classe générée par le template
string NameSpace = "T4Practice"; //Namespace de la classe générée
string folder = "Classes"; //Dossier contenant nos classes
DirectoryInfo directoryTemplate = new FileInfo(Host.TemplateFile).Directory; //répertoire contenant notre tt

Afin de rendre plus lisible le code de notre Template, nous allons le segmenter en plusieurs méthodes. La première sera chargée d'écrire les différents usings :

 
Sélectionnez

private void writeUsings(string space, string folder)
{
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using <#= space + "." + folder #>;

<#+ 
}

La dernière ligne sert à créer le using pour pouvoir disposer de nos classes. La prochaine fonction aura pour rôle d'écrire le namespace et la déclaration de la classe :

 
Sélectionnez

private void BeginHeader(string space, string nameClass)
{
	
#>
namespace <#=  space #>
{
	public class <#=  nameClass #>
	{
	
<#+ 
}

Cette fonction attend en paramètres le namespace et le nom de la classe. La troisième fonction servira à fermer les accolades à la fin de notre fichier :

 
Sélectionnez

private void EndNamespace()
{
#>
	}
}
<#+
}

Enfin, notre dernière fonction servira à écrire le code relatif à une propriété :

 
Sélectionnez

private void WriteProperty(string name)
{
#>
	public <#= String.Format("{0} {1}",name, name.ToLower()) #>  {get; set; }
	
<#+
}

Grâce à ces quatre méthodes nous allons pouvoir générer notre Template T4. Nous allons maintenant ajouter le code permettant de parcourir les fichiers concernés. Pour commencer, déclarons quelques variables :

 
Sélectionnez

string NameClass = "ClassT4";
string NameSpace = "T4Practice";
string folder = "Classes";
DirectoryInfo directoryTemplate = new FileInfo(Host.TemplateFile).Directory;
  • NameClass : nom de la classe générée par notre Template T4 ;
  • NameSpace : espace de nom dans lequel doit se situer notre classe générée ;
  • folder : nom du dossier contenant nos classes ;
  • directoryTemplate : répertoire parent de notre Template.

Maintenant, il ne nous reste plus qu'à créer le code pour remplir notre fichier de sortie :

 
Sélectionnez

writeUsings(NameSpace, folder);

BeginHeader(NameSpace, NameClass);

foreach(FileInfo file in new DirectoryInfo(directoryTemplate.FullName + @"\" + folder).GetFiles())
{
	WriteProperty(file.Name.Split('.').GetValue(0).ToString());
}

EndNamespace();
  1. On insère les différents usings ;
  2. On insère le namespace et la déclaration de la classe ;
  3. Pour chaque fichier du dossier, on va créer une propriété ;
  4. On termine en fermant les différentes accolades.

4.3. Résultat final

Nous en avons donc fini avec notre Template. Voici le résultat obtenu en entier :

 
Sélectionnez

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>
<#  
string NameClass = "ClassT4";
string NameSpace = "T4Practice";
string folder = "Classes";
DirectoryInfo directoryTemplate = new FileInfo(Host.TemplateFile).Directory;

writeUsings(NameSpace, folder);

BeginHeader(NameSpace, NameClass);

foreach(FileInfo file in new DirectoryInfo(directoryTemplate.FullName + @"\" + folder).GetFiles())
{
	WriteProperty(file.Name.Split('.').GetValue(0).ToString());
}
EndNamespace();

#>

<#+ 
private void writeUsings(string space, string folder)
{
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using <#= space + "." + folder #>;

<#+ 
}

private void BeginHeader(string space, string nameClass)
{
	
#>
namespace <#=  space #>
{
	public class <#=  nameClass #>
	{
	
<#+ 
}

private void EndNamespace()
{
#>
	}
}
<#+
}

private void WriteProperty(string name)
{
#>
	public <#= String.Format("{0} {1}",name, name.ToLower()) #>  {get; set; }
	
<#+
}

#>

Lorsque nous exécutons notre Template, nous obtenons le code suivant (en fonction des différentes classes créées) :

 
Sélectionnez

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using T4Practice.Classes;

namespace T4Practice
{
	public class ClassT4
	{
	
	public Class1 class1  {get; set; }
	
	public Class2 class2  {get; set; }
	
	}
}

5. Conclusion

À travers cet article, nous avons découvert les Templates T4. Comme vous avez pu le voir, cette technologie va nous permettre de gagner un temps considérable dans nos développements. Si l'exemple donné semble simple, sachez que vous pouvez adapter les Templates T4 à de nombreuses situations. Je vous invite donc à lire mes autres articles (Templates T4 et Entity FrameworkTemplates T4 et Entity Framework, par Kevin Perriat, Classes Métadonnées, Entity Framework et Templates T4Classes Métadonnées, Entity Framework et Templates T4, par Kevin Perriat) pour plus d'informations.

6. Remerciements

Je tiens à remercier Paul Duguet pour sa participation à la rédaction de cet article, ainsi que toute l'équipe Développez. Je remercie aussi jacques_jean et djibril pour leurs corrections, ainsi que Jean-Michel Ormes pour ses nombreux conseils.