|
| 1 | +# T4Sample (How to Use T4 in .NET Core + VSCode) |
| 2 | + |
| 3 | +This is a sample to create a table Entity class using T4. |
| 4 | + |
| 5 | +In Japanese, see also [.NET Core+VS CodeでもT4 テンプレートエンジンでコード生成したい!](https://qiita.com/nogic1008/items/2c4049d43a11e83df15b) |
| 6 | + |
| 7 | +## Environments |
| 8 | + |
| 9 | +- .NET Core 3.0 SDK (Preview 7) |
| 10 | + - For use ["default implementation of interfaces"](https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/default-interface-members-versions). |
| 11 | + |
| 12 | +- Visual Studio Code |
| 13 | + - Required: [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp) |
| 14 | + - Recommended: [T4 Support](https://marketplace.visualstudio.com/items?itemName=zbecknell.t4-support) to highlight T4 Documents. |
| 15 | + |
| 16 | +## What is "T4"? |
| 17 | + |
| 18 | +T4 means "Text Template Transformation Toolkit". |
| 19 | +It is bundled to Visual Studio since 2008. |
| 20 | + |
| 21 | +It is often used for automatic code generation such as table definition classes. |
| 22 | + |
| 23 | +This sample uses [Mono.TextTemplating](https://github.com/mono/t4) which is a T4 implemented by Mono Project. |
| 24 | + |
| 25 | +## Processes |
| 26 | + |
| 27 | +### 1. Create Project |
| 28 | + |
| 29 | +```console |
| 30 | +> dotnet new console |
| 31 | +``` |
| 32 | + |
| 33 | +### 2. Add `LangVersion` to .csproj |
| 34 | + |
| 35 | +- Set `LangVersion` to *8.0*. |
| 36 | + |
| 37 | +```diff |
| 38 | + <PropertyGroup> |
| 39 | ++ <LangVersion>8.0</LangVersion> |
| 40 | + <OutputType>Exe</OutputType> |
| 41 | + <TargetFramework>netcoreapp3.0</TargetFramework> |
| 42 | + </PropertyGroup> |
| 43 | +``` |
| 44 | + |
| 45 | +### 3. Create Table and Column Entities |
| 46 | + |
| 47 | +- [ColumnInfo.cs](./ColumnInfo.cs) |
| 48 | +- [TableInfo.cs](./TableInfo.cs) |
| 49 | + |
| 50 | +### 4. Install Mono.TextTemplating from NuGet |
| 51 | + |
| 52 | +The program code generated by T4 file depends on this package. |
| 53 | + |
| 54 | +```console |
| 55 | +> dotnet add package Mono.TextTemplating --version 2.0.5 |
| 56 | +``` |
| 57 | + |
| 58 | +### 5. Install T4 Cli Tool |
| 59 | + |
| 60 | +Add `DotNetCliToolReference` in csproj to use [dotnet-t4-project-tool](https://www.nuget.org/packages/dotnet-t4-project-tool/). |
| 61 | + |
| 62 | +```diff |
| 63 | + <ItemGroup> |
| 64 | ++ <DotNetCliToolReference Include="dotnet-t4-project-tool" Version="2.0.5" /> |
| 65 | + <PackageReference Include="Mono.TextTemplating" Version="2.0.5" /> |
| 66 | + </ItemGroup> |
| 67 | +``` |
| 68 | + |
| 69 | +### 6. Add Task to Prebuild and Cleanup |
| 70 | + |
| 71 | +#### Define Target Files |
| 72 | + |
| 73 | +Define `TextTemplate` and `Genarated` using Glob. |
| 74 | + |
| 75 | +```diff |
| 76 | + <ItemGroup> |
| 77 | + <DotNetCliToolReference Include="dotnet-t4-project-tool" Version="2.0.5" /> |
| 78 | + <PackageReference Include="Mono.TextTemplating" Version="2.0.5" /> |
| 79 | ++ <TextTemplate Include="**\*.tt" /> |
| 80 | ++ <Generated Include="**\*.Generated.cs" /> |
| 81 | + </ItemGroup> |
| 82 | +``` |
| 83 | + |
| 84 | +#### Define Prebuild Task |
| 85 | + |
| 86 | +Define Task to run `dotnet t4`. |
| 87 | + |
| 88 | +- `%(TextTemplate.Identity)` |
| 89 | + - T4 File Paths such as *foo/Template.tt*. |
| 90 | +- `$(RootNameSpace)` |
| 91 | + - Default Namespace. |
| 92 | + If you changed the T4 class's namespace, set it exactly. |
| 93 | +- `%(TextTemplate.Filename)` |
| 94 | + - T4 File Name. |
| 95 | + |
| 96 | +```diff |
| 97 | + </ItemGroup> |
| 98 | ++ <Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild"> |
| 99 | ++ <Exec WorkingDirectory="$(ProjectDir)" Command="dotnet t4 %(TextTemplate.Identity) -c $(RootNameSpace).%(TextTemplate.Filename) -o %(TextTemplate.Filename).Generated.cs" /> |
| 100 | ++ </Target> |
| 101 | +``` |
| 102 | + |
| 103 | +#### Define Cleanup Task |
| 104 | + |
| 105 | +Define Task to delete `*.Generated.cs`. |
| 106 | + |
| 107 | +```diff |
| 108 | + </Target> |
| 109 | ++ <Target Name="TextTemplateClean" AfterTargets="Clean"> |
| 110 | ++ <Delete Files="@(Generated)" /> |
| 111 | ++ </Target> |
| 112 | +``` |
| 113 | + |
| 114 | +### 7. Create T4 Interface and define implements |
| 115 | + |
| 116 | +`TransFormText()`, Called by Program to use T4 Classes are defined in *\*.Generated.cs*. |
| 117 | +But \*.Generated.cs is generated just before the build. |
| 118 | +So calling `TransFormText()` will cause a compile error because there is no definition at before build time. |
| 119 | + |
| 120 | +This sample avoids this by using the "default implementation of interfaces". |
| 121 | + |
| 122 | +```csharp |
| 123 | +using System; |
| 124 | + |
| 125 | +namespace T4Sample |
| 126 | +{ |
| 127 | + public interface ITextTemplate |
| 128 | + { |
| 129 | + string TransformText() => throw new NotImplementedException(); |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +### 8. Create T4 Template File & Class |
| 135 | + |
| 136 | +Note that T4 class should be defined with `partial` class. |
| 137 | + |
| 138 | +- [TableEntityTemplate.tt](./TableEntityTemplate.tt) |
| 139 | +- [TableEntityTemplate.cs](./TableEntityTemplate.cs) |
| 140 | + |
| 141 | +### 9. Call T4 Class in Program.cs |
| 142 | + |
| 143 | +Note that variable type should be an interface. **Don't** use `var` or `TableEntityTemplate`. |
| 144 | + |
| 145 | +- [Program.cs](./Program.cs) |
| 146 | + |
| 147 | +## Build & Run |
| 148 | + |
| 149 | +### Build |
| 150 | + |
| 151 | +```console |
| 152 | +> dotnet build |
| 153 | +``` |
| 154 | + |
| 155 | +`TableEntityTemplate.Generated.cs` is generated and the program is built including it. |
| 156 | + |
| 157 | +### Run |
| 158 | + |
| 159 | +`dotnet run` does not cause Beforebuild-Event, you should execute `dotnet build` first. |
| 160 | + |
| 161 | +```console |
| 162 | +> dotnet run |
| 163 | +``` |
| 164 | + |
| 165 | +### Result |
| 166 | + |
| 167 | +```csharp |
| 168 | +using System; |
| 169 | +using System.Collections.Generic; |
| 170 | + |
| 171 | +namespace MyNameSpace |
| 172 | +{ |
| 173 | + /// <summery> |
| 174 | + /// Stores employee information. |
| 175 | + /// </summery> |
| 176 | + public class StaffMaster |
| 177 | + { |
| 178 | + public int StaffId { get; } |
| 179 | + |
| 180 | + public string StaffName { get; set; } |
| 181 | + |
| 182 | + /// <summery> |
| 183 | + /// Home Address. |
| 184 | + /// </summery> |
| 185 | + public string Address { get; set; } |
| 186 | + |
| 187 | + public DateTime CreatedDate { get; set; } |
| 188 | + |
| 189 | + public StaffMaster( |
| 190 | + int staffId |
| 191 | + ) |
| 192 | + { |
| 193 | + StaffId = staffId; |
| 194 | + } |
| 195 | + |
| 196 | + public StaffMaster( |
| 197 | + int staffId, |
| 198 | + string staffName, |
| 199 | + string address, |
| 200 | + DateTime createdDate |
| 201 | + ) |
| 202 | + { |
| 203 | + StaffId = staffId; |
| 204 | + StaffName = staffName; |
| 205 | + Address = address; |
| 206 | + CreatedDate = createdDate; |
| 207 | + } |
| 208 | + } |
| 209 | +} |
| 210 | +``` |
| 211 | + |
| 212 | +## References |
| 213 | + |
| 214 | +- [T4 Templates at Build Time with Dotnet Core](https://notquitepure.info/2018/12/12/T4-Templates-at-Build-Time-With-Dotnet-Core/) |
| 215 | +- [Mono/T4](https://github.com/mono/t4) |
0 commit comments