Person
- int Id
- string Name
- DateTime Birthday
- Uri
- System.Text.Encoding Encoding
empty
number
- int n
- double? scale
- DayOfWeek
Text Template Transformation Toolkit (T4) はテンプレート エンジンの一つで、主に Visual Studio で使われているものです。
これを使うと、ソースコードやデータの集合などのファイルを自動生成できます。
今回は例として、次のような Markdown を記述したら、
それに対応するクラスやプロパティを C# のソースコードとして生成することを考えます。
Person
empty
number
この Markdown の仕様を次のように定めます。
以下では、このような .md ファイルを入力として、
プロパティおよびコンストラクターを持つ部分クラスを .cs ファイルに出力するように T4 で実装していきます。
まず、プロジェクトに上記の .md ファイルを追加しておきます。
そしてプロジェクトに「テキスト テンプレート (.tt)」 を追加します。
追加された .tt ファイルを、仕様に従って次のように実装します。
<#@ template debug="false" hostspecific="true" language="C#" #> | |
<#@ assembly name="System.Core" #> | |
<#@ import namespace="System.Collections.Generic" #> | |
<#@ import namespace="System.IO" #> | |
<#@ import namespace="System.Linq" #> | |
<#@ output extension=".cs" #> | |
<# | |
var types = GetTypeDefs(Host.ResolvePath("RecordTypes.md")); | |
#> | |
using System; | |
namespace RecordGenConsole | |
{ | |
<# foreach (var type in types) { #> | |
public partial class <#= type.Key #> | |
{ | |
<# foreach (var prop in type.Value) { #> | |
public <#= prop.Value #> <#= prop.Key #> { get; } | |
<# } #> | |
public <#= type.Key #>(<#= string.Join(", ", type.Value.Select(p => $"{p.Value} {ToCamel(p.Key)}")) #>) | |
{ | |
<# foreach (var prop in type.Value) { #> | |
<#= prop.Key #> = <#= ToCamel(prop.Key) #>; | |
<# } #> | |
} | |
} | |
<# } #> | |
} | |
<#+ | |
Dictionary<string, Dictionary<string, string>> GetTypeDefs(string filePath) | |
{ | |
var lines = File.ReadLines(filePath) | |
.Where(l => !string.IsNullOrWhiteSpace(l)) | |
.ToArray(); | |
var typeLines = lines | |
.Select((l, i) => new { l, i }) | |
.Where(_ => !_.l.StartsWith("-")) | |
.ToArray(); | |
return typeLines | |
.ToDictionary(_ => ToPascal(_.l.Trim()), _ => GetProps(_.i)); | |
Dictionary<string, string> GetProps(int i) => lines | |
.Skip(i + 1) | |
.TakeWhile(l => l.StartsWith("-")) | |
.Select(l => l.Trim('-', ' ').Split()) | |
.ToDictionary(p => ToPascal(GetPropName(p)), p => p[0]); | |
} | |
string GetPropName(string[] prop) => prop[prop.Length == 1 ? 0 : 1]; | |
string ToPascal(string s) => char.ToUpperInvariant(s[0]) + s.Substring(1); | |
string ToCamel(string s) => char.ToLowerInvariant(s[0]) + s.Substring(1); | |
#> |
注意点は以下の通りです。
hostspecific="true"
を指定して Host.ResolvePath
メソッドを使う <#= #>
:テキストの出力 <# #>
:コードを書ける、変数を使える <#+ #>
:メソッド、クラスなどを定義できる .tt ファイルを保存したときに処理が実行されます。
または、.tt ファイルを右クリックして [カスタム ツールの実行] を選択すれば実行されます。
これで、以下のように RecordTypes.cs が生成されます。
using System; | |
using System.Text; | |
namespace RecordGenConsole | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var person = new Person(4, "Shiro", DateTime.UtcNow, null, Encoding.UTF8); | |
var n = new Number(3, 2.5, DayOfWeek.Sunday); | |
Console.WriteLine(n.Scaled); // 7.5 | |
} | |
} | |
public partial class Number | |
{ | |
public double Scaled => (Scale ?? 1) * N; | |
} | |
} |
using System; | |
namespace RecordGenConsole | |
{ | |
public partial class Person | |
{ | |
public int Id { get; } | |
public string Name { get; } | |
public DateTime Birthday { get; } | |
public Uri Uri { get; } | |
public System.Text.Encoding Encoding { get; } | |
public Person(int id, string name, DateTime birthday, Uri uri, System.Text.Encoding encoding) | |
{ | |
Id = id; | |
Name = name; | |
Birthday = birthday; | |
Uri = uri; | |
Encoding = encoding; | |
} | |
} | |
public partial class Empty | |
{ | |
public Empty() | |
{ | |
} | |
} | |
public partial class Number | |
{ | |
public int N { get; } | |
public double? Scale { get; } | |
public DayOfWeek DayOfWeek { get; } | |
public Number(int n, double? scale, DayOfWeek dayOfWeek) | |
{ | |
N = n; | |
Scale = scale; | |
DayOfWeek = dayOfWeek; | |
} | |
} | |
} |
作成したサンプル
テストしたバージョン
参照
ビルド用 PowerShell スクリプトの Build Release (GitHub) を .NET Framework プロジェクト形式向けに提供していましたが、
今回は .NET Core プロジェクト形式向けのビルドツールを追加しました。
ツールの内容:
アセンブリのバージョン (x.y.z の z の部分) を 1 だけ増加させます。
.NET Core プロジェクト形式では、プロジェクト ファイル (.csproj) でバージョンを書き換えます。
プロジェクトを Release でビルドして、ZIP ファイルを作成します。
ビルド前にアセンブリのバージョンを増加させます。
プロジェクトを Release でビルドして、NuGet パッケージを作成します。
ビルド前にアセンブリのバージョンを増加させます。
これらのツール (PowerShell スクリプト) を使う方法としては、Visual Studio の「外部ツール」に登録するのが便利だと思います。
前回にビルド用のスクリプトを Visual Studio の外部ツールに登録する方法について書きましたが、
.NET Core 版の手順も改めて以下に書いておきます。
Build-Release/Downloads (GitHub) からツールの最新版をダウンロードして任意のフォルダーに展開します。
Visual Studio のメニューで [ツール] – [外部ツール] を選択して各スクリプトを追加していきます。
powershell.exe
-ExecutionPolicy Unrestricted "C:\scripts_folder\KTools.xxx.ps1"
$(ProjectDir)
$(SolutionDir)
でもよい
.NET Core 向けのプロジェクト テンプレートを選択してプロジェクトを作成します。
.NET Framework プロジェクトではバージョン番号などを AssemblyInfo.cs に記述しますが、
.NET Core プロジェクトではプロジェクト ファイル (.csproj) に記述します。
初期状態ではバージョンが設定されていない (その場合は 1.0.0 と判定される) ため、
プロジェクトのプロパティで [パッケージ バージョン] の値を設定しておきます。
上記の設定をして保存すると、.csproj ファイルの <Version> に反映されます。
なお、.NET Core のプロジェクト形式でも、
<TargetFramework>net45</TargetFramework>
のようにすれば .NET Framework をターゲットにすることができます。
詳細は .NET Core と .NET Standard を参照してください。
ツールの実行:
対象のプロジェクト内のファイルを開いた状態で、メニューからスクリプトを選択すると実行されます。
実行すると、ログが Visual Studio に出力されます。
同様に、メニューから Zip Release を実行します。
zip フォルダーに ZIP ファイルが作成されます。
クラス ライブラリ プロジェクトを対象に NuGet Packup を実行します。
pkg フォルダーに NuGet パッケージが作成されます。
注意点
前回: ビルド用のスクリプトを Visual Studio の外部ツールに登録する
テスト済バージョン
Visual Studio 2017
参照
Build Release (GitHub)
外部ツールの管理
.nuspec File Reference for NuGet
以前にビルドして ZIP にする PowerShell スクリプトを作成しましたが、
そのときはプロジェクトごとに NuGet でインストールする方法を前提としていました。
今回は各スクリプトを Visual Studio の外部ツールとして登録する方法も便利だとわかったため、その利用手順を紹介します。
設定手順:
powershell.exe
-ExecutionPolicy Unrestricted "C:\scripts_folder\KTools.xxx.ps1"
$(ProjectDir)
$(SolutionDir)
でもよい
以上の設定で、「プロジェクト フォルダー上で PowerShell スクリプトを実行する」ためのメニューが
Visual Studio の [ツール] メニューに追加されました。
実行するには、対象のプロジェクトのファイルを開いているときにメニューからそれらを選択します。
[出力ウィンドウを使用] がオンに設定されていると、ログが Visual Studio に出力されます。
このように Visual Studio の外部ツールを利用することで、
バージョンアップ、Release ビルド、ZIP 作成が Visual Studio から簡単にできるようになりました。
このツールは .NET Framework プロジェクト形式向けに提供していますが、
次回は .NET Core プロジェクト形式向けのツールを追加します。
テスト済バージョン
Visual Studio 2017
参照
Build Release (GitHub)
外部ツールの管理
Visual Studioの外部ツール機能を活用してみよう
ビルドして ZIP にする PowerShell スクリプト
.NET Core の登場以降、Visual Studio で新しいプロジェクトを作成しようとすると、
従来の .NET Framework のほかに .NET Core と .NET Standard 向けのプロジェクト テンプレートが現れます。
それぞれのプロジェクトにおけるアセンブリの参照可否をまとめると次のようになります。
.NET Framework と .NET Core はランタイムが異なるため、
両方に対応するクロスプラットフォームのクラス ライブラリを作成するには .NET Standard をターゲットにします。
なお、.NET Standard 2.0 アセンブリは .NET Framework 4.6.1 以上で参照可能です。
.NET Core および .NET Standard のプロジェクト テンプレートには、次の特徴があります。
クラス ライブラリの .csproj ファイルの内容は次のようになっています。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
TargetFramework を TargetFrameworks に変更すれば、対象のフレームワークをセミコロン区切りで複数指定できます。
ここで指定する netstandard2.0
や net40
は、Target Framework Moniker と呼ばれます。
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
これで複数のフレームワークを対象にしたアセンブリを一度にビルドできます。
.NET Framework 向けのみのアセンブリを作成したい場合であっても、
.NET Core 向けのテンプレートから作成して TargetFramework を変更する方法が有効です。
次に、OutputType
に Exe
を指定すればコンソール アプリになります (指定がなければクラス ライブラリ)。
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net45</TargetFrameworks>
コンソール アプリをビルドすると、.NET Framework 向けでは .exe が生成されますが、.NET Core 向けでは .dll となります。
(自己完結型デプロイにより、各プラットフォーム向けの実行可能ファイルを生成することもできます。ただし 60MB 前後になります。)
DLL の状態の .NET Core 向けアプリを実行するには、dotnet コマンドを実行します。
dotnet ConsoleApp1.dll
その他の注意点
作成したサンプル
バージョン情報
参照
以前に .NET ビルド小技集 (4) という記事を書き、
PowerShell でバージョンをインクリメントしてビルドする方法を紹介しました。
今回は、そのツールを改良したうえで NuGet で公開しました。
Visual Studio のプロジェクトに対して、NuGet で KTools.ZipRelease をインストールすると、
次の PowerShell ファイルがプロジェクトに追加されます。
エクスプローラー上で PowerShell スクリプトを実行できます。
KTools.ZipRelease.ps1 により、以下の処理が実行されます。
KTools.VersionIncrement.ps1 により、AssemblyInfo.cs 内の
AssemblyVersion 属性および AssemblyFileVersion 属性の値のビルド番号を 1 だけ増加させています。
例えば、1.0.2.0 が 1.0.3.0 に、1.0.2 が 1.0.3 に、1.0.2-alpha が 1.0.3-alpha に変わります。
ちなみに、バージョン番号は .exe および .dll ファイルのプロパティに反映されます。
PowerShell スクリプトのため、各自の要件に合わせてカスタマイズできるでしょう。
また、バージョン番号のインクリメントについては、
KTools.VersionIncrement として単独でインストールして使うことができます。
技術的には、以下の特徴が挙げられます。
ソースコードは Build Release (GitHub) にあります。
追記: ビルド用のスクリプトを Visual Studio の「外部ツール」に登録すると便利です。
また、.NET Core プロジェクト形式向けのビルド スクリプトも追加しました。
作成したツール
Build Release (GitHub)
参照
.NET ビルド小技集 (4)
.NET Framework の正規表現
.nuspec リファレンス
NuGet Package Version Reference