-
Generate variable aspects of the application.
-
Code generation is most useful for those aspects of the application that might change during the project, or will change between different versions of the application. Separate these variable aspects from the more invariant aspects so that you can more easily determine what has to be generated. For example, if your application provides a Web site, separate the standard page serving functions from the logic that defines the navigation paths from one page to another.
-
Encode the variable aspects in one or more source models.
-
A model is a file or database that each template reads to obtain specific values for variable parts of the code that is to be generated. Models can be databases, XML files of your own design, diagrams, or domain-specific languages. Typically, one model is used to generate many files in a Visual Studio project. Each file is generated from a separate template.
You can use more than one model in a project. For example, you might define a model for navigation between Web pages, and a separate model for the layout of the pages.
-
Focus the model on the users' needs and vocabulary, not on your implementation.
-
For example, in a Web site application, you would expect the model to refer to Web pages and hyperlinks.
Ideally, choose a form of presentation that suits the kind of information that the model represents. For example, a model of navigation paths through a Web site could be a diagram of boxes and arrows.
-
Test the generated code.
-
Use manual or automated tests to verify that the resulting code works as the users require. Avoid generating tests from the same model from which the code is generated.
In some cases, general tests can be performed on the model directly. For example, you could write a test that ensures that every page in the Web site can be reached by navigation from any other.
-
Allow for custom code: generate partial classes.
-
Allow for code that you write by hand in addition to the generated code. It is unusual for a code generation scheme to be able to account for all possible variations that might arise. Therefore, you should expect to add to or override some of the generated code. Where the generated material is in a .NET language such as Visual C# or Visual Basic, two strategies are especially useful:
-
The generated classes should be partial. This lets you to add content to the generated code.
-
Classes should be generated in pairs, one inheriting from the other. The base class should contain all the generated methods and properties, and the derived class should contain only the constructors. This allows your hand-written code to override any of the generated methods.
In other generated languages such as XML, use the <#@include#> directive to make simple combinations of hand-written and generated content. In more complex cases, you might have to write a post-processing step that combines the generated file with any hand-written files.
-
Move common material into include files or run-time templates
-
To avoid repeating similar blocks of text and code in multiple templates, use the <#@ include #> directive. For more information, see T4 Include Directive.
You can also build run-time text templates in a separate project, and then call them from the design-time template. To do this, use the <#@ assembly #> directive to access the separate project. For examples, see "Inheritance in Text Templates" in Gareth Jones’ Blog.
-
Consider moving large blocks of code into a separate assembly.
-
If you have large code blocks and class feature blocks, it might be useful to move some of this code into methods that you compile in a separate project. You can use the <#@ assembly #> directive to access the code in the template. For more information, see T4 Assembly Directive.
You can put the methods in an abstract class that the template can inherit. The abstract class must inherit from Microsoft.VisualStudio.TextTemplating.TextTransformation. For more information, see T4 Template Directive.
-
Generate code, not configuration files
-
One method of writing a variable application is to write generic program code that accepts a configuration file. An application written in this manner is very flexible, and can be reconfigured when the business requirements change, without rebuilding the application. However, a drawback of this approach is that the application will perform less well than a more specific application. Also, its program code will be more difficult to read and maintain, partly because it has always to deal with the most generic types.
By contrast, an application whose variable parts are generated before compilation can be strongly typed. This makes it much easier and more reliable to write hand-written code and integrate it with the generated parts of the software.
To obtain the full benefit of code generation, try to generate program code instead of configuration files.
-
Use a Generated Code folder
-
Place the templates and the generated files in a project folder named Generated Code, to make it clear that these are not files that should be edited directly. If you create custom code to override or add to the generated classes, place those classes in a folder that is named Custom Code. The structure of a typical project looks like this:
MyProject
Custom Code
Class1.cs
Class2.cs
Generated Code
Class1.tt
Class1.cs
Class2.tt
Class2.cs
AnotherClass.cs