Search code examples
c#visual-studiocode-generationt4texttemplate

Process multiple T4 templates with custom tool


I've got a DSL model and multiple T4 templates that generate code corresponding to the model. What I want to do is that ALL templates are executed upon save of the model. Each template creates multiple output files. I know theoretically how to create a custom tool for the model that will process a template and return the generated code. But how can I process multiple templates, since the IVsSingleFileGenerator interface returns a single generated file.

One way I think about is to create a "master" T4 that uses public methods from the templates that shall be processed. But then I've to write ugly methods in each template with hundreds of "Write()" calls because inside of a "<#+" it's not possible to write plain text like in the rest of the template. Or I could create one huge template that contains the code for ALL files to be generated. But that's ugly and very confusing I think.

Or is there a way to somehow instantiate a T4 template and let it process and create the files on it's own? I know only how to instantiate the template so that it can be processed but I only get the generated code that I've to handle self.


Solution

  • I didn't know how to generate text from a class feature (<#+) but it's described in MSDN:

    Generate text from a class feature

    <#+
    private void CreateAccessor(ModelClass classType, ModelClass associatedClass, string      fromRoleName, string toRoleName)
    {
                if(!string.IsNullOrEmpty(toRoleName) && !string.IsNullOrEmpty(fromRoleName))
                {
                   string validClassName = MakeValidName(associatedClass.Name);
                   string validFromName = MakeValidName(fromRoleName);
                   string validToName = MakeValidName(toRoleName);
    #>
    
    private <#= validClassName#> <#= validFromName#>Value;
    public <#= validClassName#> <#= validFromName#>
    {
        get{ return <#= validFromName #>Value; }
        set
        {
           if (<#= validFromName#> != value)
           {
    if (<#= validFromName#> != null) 
    <#= validFromName#>.<#=validToName#> = null;
    <#= validFromName#>Value = value;
    if (value != null) 
    {
            <#= validFromName#>Value.<#=validToName#>=this;
    }
       }
            }
        }
    <#+
                }
                else
                {
                    Warning(String.Format("Ignoring BidirectionalAssociation from {0} to {1} because its SourceRoleName or TargetRoleName is not defined", classType.Name, associatedClass.Name));
                }
    }
    #>