C#テンプレート完全ガイド|初心者でもすぐ使える書き方・作り方・実践例
はじめに
「csharp template」と検索すると、C#のジェネリック、Visual Studioのテンプレート、dotnet newテンプレート、文字列テンプレート、Template Methodパターンなど、複数の意味が出てきます。
そのため、初心者にとっては「C#テンプレートとは結局どれのこと?」と混乱しやすいテーマです。
この記事では、C#におけるテンプレートの意味を整理しながら、ジェネリックの基本、Visual Studioテンプレート、dotnet newテンプレート、文字列テンプレート、Template Methodパターンまで、実践で使える形で解説します。
1. C#テンプレートとは?csharp templateで調べる人が知りたい意味を整理
C#で「テンプレート」と呼ばれるものは1つではありません。文脈によって意味が変わるため、まずは全体像を押さえることが大切です。
1-1. C#における「テンプレート」は主に4種類ある
C#でテンプレートと呼ばれるものは、主に次の4種類です。
1つ目は、型を汎用化する「ジェネリック」です。List<T>やDictionary<TKey, TValue>のように、型を後から指定できる仕組みです。
2つ目は、Visual Studioやdotnet CLIで使う「プロジェクトテンプレート」です。新しいプロジェクトやクラスを決まった構成で作成できます。
3つ目は、文字列やコードを生成する「文字列テンプレート」です。メール本文、HTML、SQLなどを動的に作るときに使います。
4つ目は、設計パターンとしての「Template Methodパターン」です。処理の流れを親クラスに定義し、一部の処理を子クラスで差し替える考え方です。
1-2. C++のtemplateとC#のtemplateは同じではない
C++にはtemplateというキーワードがありますが、C#には同じ意味のtemplateキーワードはありません。
C++のtemplateはコンパイル時に型ごとのコードを生成する仕組みです。一方、C#では主に「ジェネリック」が同じような役割を担います。
つまり、csharp templateと検索している場合、多くは「C#でC++のtemplateのようなことをしたい」という意図であり、C#ではジェネリックを学ぶのが第一歩です。
1-3. C#では「ジェネリック」がテンプレート的な役割を担う
C#で型に依存しない共通処理を書きたい場合は、ジェネリックを使います。
C#public T Echo<T>(T value)
{
return value;
}
このコードでは、Tが型の placeholder のような役割をします。intでもstringでも、同じメソッドを使えます。
C#Console.WriteLine(Echo<int>(10));
Console.WriteLine(Echo<string>("Hello"));
このように、C#のジェネリックは「型を後から指定できるテンプレート」と考えると理解しやすくなります。
1-4. プロジェクト作成を効率化するVisual Studio/dotnet newテンプレート
C#のテンプレートには、プロジェクトやファイルのひな形という意味もあります。
たとえばVisual Studioで「コンソールアプリ」「ASP.NET Core Web API」「クラスライブラリ」を選んで作成する機能もテンプレートです。
CLIでは次のように使います。
Bashdotnet new console -n SampleApp
このコマンドは、コンソールアプリのテンプレートを使ってSampleAppというプロジェクトを作成します。
1-5. 文字列・コード生成・デザインパターンとしてのテンプレート
C#では、文字列生成でもテンプレートという言葉を使います。
C#string name = "Taro";
string message = $"こんにちは、{name}さん";
また、HTMLやメール本文を生成する場合は、RazorやScribanなどのテンプレートエンジンを使うこともあります。
さらに、オブジェクト指向設計ではTemplate Methodパターンという設計手法もあります。
このように、C#テンプレートは「型の再利用」「プロジェクト作成」「文字列生成」「設計パターン」の4つに分けて理解すると整理しやすいです。
2. C#テンプレートの基本|初心者が最初に理解すべき考え方
C#テンプレートを理解するうえで重要なのは、「何を再利用したいのか」を明確にすることです。
2-1. テンプレートを使う目的は「再利用」と「型安全」
テンプレートを使う目的は、同じようなコードを何度も書かずに再利用することです。
さらにC#のジェネリックでは、型安全を保ったまま再利用できます。
たとえばobject型を使えば何でも受け取れますが、実行時に型変換エラーが起きる可能性があります。
C#object value = "100";
int number = (int)value; // 実行時エラー
一方、ジェネリックを使うとコンパイル時に型をチェックできます。
C#public T GetValue<T>(T value)
{
return value;
}
2-2. 同じ処理を複数の型で使い回せる
ジェネリックを使うと、int用、string用、DateTime用のように似たメソッドを何度も書く必要がありません。
C#public void Print<T>(T value)
{
Console.WriteLine(value);
}
使い方は次の通りです。
C#Print(123);
Print("Hello");
Print(DateTime.Now);
型が違っても、共通の処理を1つにまとめられます。
2-3. コピペコードを減らして保守性を高められる
テンプレートを使う最大のメリットは、コピペコードを減らせることです。
同じ処理を複数箇所に書くと、修正が必要になったときにすべての箇所を直さなければなりません。
ジェネリックやテンプレート化を使えば、共通処理を1か所に集約できます。
その結果、バグの混入を防ぎやすくなり、保守性も高まります。
2-4. C#でテンプレートが必要になる代表的な場面
C#でテンプレートが必要になる場面は多くあります。
たとえば、APIレスポンスの型を共通化したい場合、Repositoryクラスを複数のエンティティで使い回したい場合、似た構成のプロジェクトを何度も作る場合、メール本文を動的に生成したい場合などです。
これらはすべて「毎回ゼロから書くのは非効率」という共通点があります。
2-5. ジェネリック・プロジェクトテンプレート・文字列テンプレートの使い分け
型を汎用化したいならジェネリックを使います。
プロジェクトやクラスのひな形を作りたいなら、Visual Studioテンプレートやdotnet newテンプレートを使います。
文字列やHTMLを動的に作りたいなら、文字列補間、StringBuilder、テンプレートエンジンを使います。
このように、目的に応じて適切なテンプレートを選ぶことが重要です。
3. C#でテンプレート的に使えるジェネリックの書き方
C#で最も基本となるテンプレート的な機能がジェネリックです。
3-1. ジェネリックとは
ジェネリックとは、型を固定せずにクラスやメソッドを定義できる仕組みです。
C#public class Box<T>
{
public T Value { get; set; }
}
Tは型パラメーターです。実際に使うときにintやstringなどを指定します。
C#var intBox = new Box<int>();
intBox.Value = 100;
var stringBox = new Box<string>();
stringBox.Value = "Hello";
3-2. ジェネリックメソッドの基本構文
ジェネリックメソッドは、メソッド名の後ろに<T>を付けて定義します。
C#public static T GetFirst<T>(T[] values)
{
return values[0];
}
使い方は次の通りです。
C#int firstNumber = GetFirst(new int[] { 1, 2, 3 });
string firstText = GetFirst(new string[] { "A", "B", "C" });
型推論が働くため、GetFirst<int>のように明示しなくても使えることが多いです。
3-3. ジェネリッククラスの基本構文
ジェネリッククラスは、クラス名の後ろに<T>を付けます。
C#public class Repository<T>
{
private readonly List<T> _items = new();
public void Add(T item)
{
_items.Add(item);
}
public IEnumerable<T> GetAll()
{
return _items;
}
}
このクラスは、任意の型のデータを扱えます。
C#var userRepository = new Repository<User>();
var productRepository = new Repository<Product>();
3-4. ジェネリックインターフェースの使い方
インターフェースにもジェネリックを使えます。
C#public interface IRepository<T>
{
void Add(T item);
T? FindById(int id);
}
実装例は次の通りです。
C#public class UserRepository : IRepository<User>
{
public void Add(User item)
{
// 保存処理
}
public User? FindById(int id)
{
// 検索処理
return null;
}
}
共通の設計を保ちながら、型ごとの実装を分けられます。
3-5. 型パラメーターTの意味と命名ルール
TはTypeの頭文字です。単一の型パラメーターではTを使うのが一般的です。
複数の型を扱う場合は、意味が分かる名前にします。
C#public class Pair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
よく使われる命名には、T、TEntity、TKey、TValue、TResultなどがあります。
3-6. where制約の使い方
where制約を使うと、型パラメーターに条件を付けられます。
C#public class Repository<T> where T : class
{
}
この場合、Tには参照型だけを指定できます。
よく使う制約は次のようなものです。
C#where T : class
where T : struct
where T : new()
where T : BaseEntity
where T : IComparable<T>
たとえば、引数同士を比較したい場合はIComparable<T>を制約にできます。
C#public static T Max<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) >= 0 ? a : b;
}
3-7. List<T>やDictionary<TKey, TValue>で理解する実用例
C#で最もよく使うジェネリックの例がList<T>です。
C#List<string> names = new List<string>();
names.Add("Taro");
names.Add("Hanako");
List<string>では文字列だけを入れられます。誤って数値を追加しようとするとコンパイルエラーになります。
C#Dictionary<int, string> users = new Dictionary<int, string>();
users.Add(1, "Taro");
users.Add(2, "Hanako");
Dictionary<TKey, TValue>では、キーと値の型をそれぞれ指定できます。
3-8. 初心者がつまずきやすいジェネリックのエラーと解決方法
初心者がよくつまずくのは、型制約が足りないケースです。
たとえば、次のコードはコンパイルできません。
C#public T Create<T>()
{
return new T();
}
Tに引数なしコンストラクターがあるとは限らないためです。
解決するにはnew()制約を付けます。
C#public T Create<T>() where T : new()
{
return new T();
}
また、Tのプロパティに直接アクセスしようとしてエラーになることもあります。
C#public void PrintName<T>(T item)
{
Console.WriteLine(item.Name); // エラー
}
この場合は、インターフェース制約を使います。
C#public interface IHasName
{
string Name { get; }
}
public void PrintName<T>(T item) where T : IHasName
{
Console.WriteLine(item.Name);
}
4. C#テンプレートの実践例|すぐ使えるジェネリックコード
ここからは、実務でも使いやすいC#テンプレートの実践例を紹介します。
4-1. 汎用的な比較メソッドを作る
大小比較できる型に対して、汎用的な比較メソッドを作ります。
C#public static T GetMax<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) >= 0 ? a : b;
}
使用例です。
C#Console.WriteLine(GetMax(10, 20));
Console.WriteLine(GetMax("apple", "banana"));
IComparable<T>を制約にすることで、比較可能な型だけを受け付ける安全なメソッドになります。
4-2. 共通レスポンスクラスを作る
API開発では、成功・失敗・データをまとめた共通レスポンス型がよく使われます。
C#public class ApiResponse<T>
{
public bool Success { get; set; }
public string? Message { get; set; }
public T? Data { get; set; }
public static ApiResponse<T> Ok(T data)
{
return new ApiResponse<T>
{
Success = true,
Data = data
};
}
public static ApiResponse<T> Fail(string message)
{
return new ApiResponse<T>
{
Success = false,
Message = message
};
}
}
使用例です。
C#var response = ApiResponse<User>.Ok(user);
User、Product、Orderなど、さまざまな型で同じレスポンス構造を使えます。
4-3. Repositoryクラスをジェネリック化する
データアクセス処理では、Repositoryをジェネリック化すると重複を減らせます。
C#public interface IRepository<T>
{
Task<T?> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task AddAsync(T entity);
}
実装例です。
C#public class Repository<T> : IRepository<T> where T : class
{
private readonly List<T> _items = new();
public Task<T?> GetByIdAsync(int id)
{
return Task.FromResult<T?>(null);
}
public Task<IEnumerable<T>> GetAllAsync()
{
return Task.FromResult<IEnumerable<T>>(_items);
}
public Task AddAsync(T entity)
{
_items.Add(entity);
return Task.CompletedTask;
}
}
実際の開発ではEntity Framework Coreと組み合わせることも多いです。
4-4. DTOやResult型をテンプレート化する
処理結果を表すResult型も、ジェネリックと相性が良いです。
C#public class Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
private Result(bool isSuccess, T? value, string? error)
{
IsSuccess = isSuccess;
Value = value;
Error = error;
}
public static Result<T> Success(T value)
{
return new Result<T>(true, value, null);
}
public static Result<T> Failure(string error)
{
return new Result<T>(false, default, error);
}
}
使用例です。
C#Result<User> result = Result<User>.Success(user);
処理の成功・失敗を明確に表現できるため、例外に頼りすぎない設計にできます。
4-5. 型ごとに同じ処理を書かないための設計例
たとえば、CSV出力処理を複数の型で使いたい場合、ジェネリックメソッドにできます。
C#public static void Export<T>(IEnumerable<T> items)
{
foreach (var item in items)
{
Console.WriteLine(item);
}
}
ただし、プロパティ名や出力形式を細かく制御したい場合は、インターフェースや属性を組み合わせるとよいでしょう。
C#public interface ICsvWritable
{
string ToCsv();
}
public static void ExportCsv<T>(IEnumerable<T> items) where T : ICsvWritable
{
foreach (var item in items)
{
Console.WriteLine(item.ToCsv());
}
}
4-6. ジェネリックを使うべきケース・使わないほうがよいケース
ジェネリックを使うべきなのは、複数の型で同じ処理を安全に使い回したい場合です。
一方で、1つの型でしか使わない処理を無理にジェネリック化する必要はありません。
また、型ごとに処理内容が大きく違う場合も、ジェネリックよりインターフェース、継承、Strategyパターンを検討したほうが分かりやすいことがあります。
5. Visual StudioでC#テンプレートを作成する方法
C#テンプレートには、Visual Studioで使えるテンプレートもあります。
5-1. Visual Studioテンプレートとは
Visual Studioテンプレートとは、プロジェクトやファイルのひな形を作成する機能です。
毎回同じ構成のクラス、設定ファイル、プロジェクトを作る場合に便利です。
たとえば、独自のServiceクラス、Controllerクラス、Repositoryクラスなどをテンプレート化できます。
5-2. 項目テンプレートとプロジェクトテンプレートの違い
Visual Studioテンプレートには、主に項目テンプレートとプロジェクトテンプレートがあります。
項目テンプレートは、クラスファイルや設定ファイルなど、単体ファイルのひな形です。
プロジェクトテンプレートは、複数のファイルやフォルダを含むプロジェクト全体のひな形です。
クラスを追加するだけなら項目テンプレート、アプリ全体の構成を再利用したいならプロジェクトテンプレートを使います。
5-3. 既存クラスから項目テンプレートを作る手順
項目テンプレートを作る基本的な流れは次の通りです。
まず、テンプレート化したいクラスを作成します。
C#namespace $rootnamespace$
{
public class $safeitemname$
{
public void Execute()
{
}
}
}
次に、Visual Studioの「テンプレートのエクスポート」機能を使って、項目テンプレートとして出力します。
作成したテンプレートは、新しい項目の追加画面から選択できるようになります。
5-4. プロジェクトテンプレートを作る手順
プロジェクトテンプレートでは、既存プロジェクトをひな形としてエクスポートします。
基本手順は、再利用したいプロジェクト構成を作成し、不要なビルド成果物を削除し、テンプレートとしてエクスポートする流れです。
プロジェクト名、名前空間、ファイル名などは置換パラメーターを使うと、作成時の名前に合わせて変更できます。
5-5. .vstemplateファイルの基本構成
Visual Studioテンプレートでは、.vstemplateファイルがテンプレートの定義ファイルになります。
簡単な例は次の通りです。
XML<VSTemplate Version="3.0.0" Type="Item"
xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>My Class Template</Name>
<Description>Custom C# class template</Description>
<ProjectType>CSharp</ProjectType>
</TemplateData>
<TemplateContent>
<ProjectItem ReplaceParameters="true">MyClass.cs</ProjectItem>
</TemplateContent>
</VSTemplate>
TemplateDataには名前や説明を定義し、TemplateContentにはテンプレートに含めるファイルを指定します。
5-6. テンプレート内で使える置換パラメーター
Visual Studioテンプレートでは、特定のパラメーターを使って名前を置換できます。
よく使うものは次の通りです。
$safeitemname$は作成された項目名、$rootnamespace$はルート名前空間、$projectname$はプロジェクト名を表します。
C#namespace $rootnamespace$
{
public class $safeitemname$
{
}
}
このように書いておくと、ファイル作成時の名前に合わせてクラス名や名前空間を変更できます。
5-7. 作成したテンプレートを追加・使用する方法
エクスポートしたテンプレートは、Visual Studioのテンプレートフォルダに配置することで使用できます。
通常はZIP形式で管理され、新しい項目や新しいプロジェクトの作成画面に表示されます。
チームで共有する場合は、テンプレートファイルをリポジトリに置き、導入手順をREADMEに書いておくと便利です。
5-8. Visual Studioテンプレートが表示されないときの対処法
テンプレートが表示されない場合は、まず配置場所を確認します。
次に、.vstemplateファイルのXML構文が正しいか、ProjectTypeがCSharpになっているか、ZIP内の階層が正しいかを確認します。
Visual Studioを再起動すると表示される場合もあります。
また、テンプレートキャッシュの影響で反映されないこともあるため、テンプレートの再インポートやキャッシュ更新も確認しましょう。
6. dotnet newで使えるC#テンプレートの作り方
CLIでC#テンプレートを作るなら、dotnet newテンプレートが便利です。
6-1. dotnet newテンプレートとは
dotnet newテンプレートとは、.NET CLIでプロジェクトやファイルを生成するためのテンプレートです。
Bashdotnet new console -n MyApp
このように、コマンドだけで決まった構成のプロジェクトを作れます。
独自テンプレートを作れば、チーム標準の構成を簡単に配布できます。
6-2. Visual Studioテンプレートとの違い
Visual StudioテンプレートはIDE上での操作に向いています。
一方、dotnet newテンプレートはCLIで使えるため、Windows、macOS、Linuxなど環境を問わず利用しやすいです。
CI/CDやチーム開発で再利用するなら、dotnet newテンプレートのほうが扱いやすい場合があります。
6-3. テンプレート用フォルダ構成の作り方
基本的な構成は次のようになります。
MyTemplate/
.template.config/
template.json
src/
Program.cs
MyTemplate.csproj
.template.config/template.jsonがテンプレート定義ファイルです。
テンプレート化したいプロジェクトやファイルを同じフォルダ内に配置します。
6-4. .template.config/template.jsonの基本
template.jsonには、テンプレートの名前、識別子、短縮名などを定義します。
JSON{
"$schema": "http://json.schemastore.org/template",
"author": "YourName",
"classifications": [ "C#", "Console" ],
"identity": "YourCompany.ConsoleTemplate",
"name": "Custom Console App",
"shortName": "custom-console",
"sourceName": "MyTemplate"
}
sourceNameに指定した文字列は、生成時のプロジェクト名に置換されます。
6-5. shortName・identity・nameの設定方法
shortNameは、dotnet newで指定する短い名前です。
Bashdotnet new custom-console -n SampleApp
identityはテンプレートを一意に識別する名前です。通常は会社名やプロジェクト名を含めます。
nameは一覧に表示される分かりやすいテンプレート名です。
6-6. パラメーターを使ってプロジェクト名や名前空間を置換する
sourceNameを使うと、テンプレート内の文字列を生成時の名前に置換できます。
たとえば、テンプレート内でMyTemplateという名前空間を使っている場合、次のように設定します。
JSON{
"sourceName": "MyTemplate"
}
そして生成します。
Bashdotnet new custom-console -n SampleApp
すると、MyTemplateがSampleAppに置換されます。
6-7. dotnet new installでテンプレートをインストールする
作成したテンプレートは、次のコマンドでインストールできます。
Bashdotnet new install ./MyTemplate
NuGetパッケージとして配布している場合も、同じようにインストールできます。
Bashdotnet new install Your.Template.Package
6-8. dotnet new listでテンプレートを確認する
インストール済みテンプレートは、次のコマンドで確認できます。
Bashdotnet new list
作成したshortNameが一覧に表示されていれば、テンプレートを使用できます。
6-9. 作成したテンプレートを使ってプロジェクトを生成する
テンプレートを使ってプロジェクトを作成します。
Bashdotnet new custom-console -n SampleApp
生成後、ビルドして動作確認します。
Bashcd SampleApp
dotnet build
dotnet run
6-10. dotnet newテンプレート作成時のよくあるエラー
よくあるエラーは、template.jsonのJSON構文ミスです。カンマの付け忘れや余分なカンマに注意しましょう。
また、shortNameが他のテンプレートと重複していると分かりにくくなります。
sourceNameの指定が実際の名前空間やプロジェクト名と一致していない場合、置換されないこともあります。
テンプレートが認識されない場合は、.template.config/template.jsonの配置場所を確認してください。
7. 文字列テンプレート・コード生成としてのC#テンプレート
C#では、文字列を動的に生成する場面でもテンプレートを使います。
7-1. 文字列テンプレートとは
文字列テンプレートとは、固定の文章や構造の一部を変数で置き換える仕組みです。
たとえば、ユーザー名だけを差し替えてメール本文を作る場合などに使います。
7-2. 文字列補間を使ったシンプルなテンプレート
最も簡単なのは、文字列補間です。
C#string name = "Taro";
string message = $"こんにちは、{name}さん。ご登録ありがとうございます。";
複雑でない文章なら、文字列補間だけで十分です。
7-3. StringBuilderを使ったテンプレート生成
長い文字列を組み立てる場合は、StringBuilderが便利です。
C#var builder = new StringBuilder();
builder.AppendLine("<html>");
builder.AppendLine("<body>");
builder.AppendLine($"<h1>{title}</h1>");
builder.AppendLine($"<p>{message}</p>");
builder.AppendLine("</body>");
builder.AppendLine("</html>");
string html = builder.ToString();
複数行のHTMLやメール本文を作るときに使いやすい方法です。
7-4. メール本文・SQL・HTML生成での活用例
メール本文の例です。
C#string body = $"""
{name} 様
ご注文ありがとうございます。
注文番号は {orderNumber} です。
今後ともよろしくお願いいたします。
""";
HTML生成の例です。
C#string html = $"<h1>{title}</h1><p>{content}</p>";
SQLを動的に作る場合は注意が必要です。文字列連結でユーザー入力を埋め込むとSQLインジェクションの危険があります。
悪い例です。
C#string sql = $"SELECT * FROM Users WHERE Name = '{name}'";
安全にするには、パラメーター化クエリを使いましょう。
7-5. RazorやScribanなどテンプレートエンジンを使う選択肢
HTMLやメール本文が複雑になる場合は、テンプレートエンジンを使うと管理しやすくなります。
RazorはASP.NET Coreでよく使われるテンプレート構文です。
Scribanは、テキストテンプレートやコード生成で使いやすいテンプレートエンジンです。
テンプレートエンジンを使うと、文章やHTMLをC#コードから分離できます。
7-6. 文字列テンプレートで注意すべきセキュリティ
文字列テンプレートでは、ユーザー入力の扱いに注意が必要です。
HTMLに埋め込む場合はXSS対策が必要です。
SQLに埋め込む場合はSQLインジェクション対策が必要です。
ファイルパスやコマンド文字列に埋め込む場合も、不正な入力による危険があります。
テンプレートは便利ですが、外部入力をそのまま埋め込まないことが重要です。
7-7. テンプレートエンジンを使うべきケース・不要なケース
短い文字列なら、文字列補間で十分です。
長いHTML、複雑なメール本文、多言語対応、非エンジニアが文面を編集するケースでは、テンプレートエンジンを使う価値があります。
逆に、単純なメッセージ生成にテンプレートエンジンを導入すると、かえって複雑になることもあります。
8. Template MethodパターンとしてのC#テンプレート
C#テンプレートには、デザインパターンとしての意味もあります。
8-1. Template Methodパターンとは
Template Methodパターンとは、処理の大きな流れを親クラスに定義し、一部の処理を子クラスで実装する設計パターンです。
共通処理を親クラスにまとめ、変化する部分だけを子クラスに任せます。
8-2. 処理の流れだけを親クラスに定義する考え方
たとえば、レポート生成処理を考えます。
データ取得、加工、出力という流れは共通でも、データ取得方法や出力形式は種類によって異なることがあります。
このような場合にTemplate Methodパターンが使えます。
8-3. 抽象クラスとoverrideを使った実装例
実装例です。
C#public abstract class ReportGenerator
{
public void Generate()
{
var data = LoadData();
var formatted = FormatData(data);
Save(formatted);
}
protected abstract string LoadData();
protected virtual string FormatData(string data)
{
return data.Trim();
}
protected abstract void Save(string data);
}
子クラスで具体的な処理を実装します。
C#public class CsvReportGenerator : ReportGenerator
{
protected override string LoadData()
{
return " csv data ";
}
protected override void Save(string data)
{
Console.WriteLine($"CSV出力: {data}");
}
}
8-4. 共通処理と個別処理を分ける設計例
Template Methodパターンでは、共通の流れを親クラスに閉じ込められます。
C#var generator = new CsvReportGenerator();
generator.Generate();
利用側はGenerateを呼ぶだけでよく、細かい処理順序を知る必要がありません。
8-5. Template Methodパターンのメリット
メリットは、処理の流れを統一できることです。
共通処理を親クラスにまとめられるため、重複コードを減らせます。
また、子クラスでは差し替えたい部分だけを実装すればよくなります。
8-6. 継承に頼りすぎるデメリットと注意点
Template Methodパターンは継承を使うため、親クラスと子クラスの結合が強くなりやすいです。
また、階層が深くなると処理の流れが追いにくくなります。
継承を使う前に、本当に「共通の処理順序」が必要かを確認しましょう。
8-7. Strategyパターンやインターフェースとの使い分け
処理の流れを固定したい場合はTemplate Methodパターンが向いています。
一方、処理そのものを自由に差し替えたい場合はStrategyパターンが向いています。
また、単に共通の契約を定義したいだけならインターフェースで十分です。
9. C#テンプレートを使うときのベストプラクティス
C#テンプレートを効果的に使うには、いくつかのポイントがあります。
9-1. 目的に合ったテンプレート方式を選ぶ
型を再利用したいならジェネリック、プロジェクト構成を再利用したいならdotnet newテンプレート、文字列を生成したいなら文字列テンプレートを使います。
目的が違うのに無理に同じ方法で解決しようとすると、コードが複雑になります。
9-2. 汎用化しすぎない
テンプレート化は便利ですが、汎用化しすぎると読みづらくなります。
特に初心者のうちは、「本当に複数箇所で使うのか」を確認してからテンプレート化しましょう。
1回しか使わない処理を無理にジェネリック化する必要はありません。
9-3. 命名規則を統一する
ジェネリックの型パラメーター名やテンプレート名は、チーム内で統一しましょう。
TEntity、TKey、TValueなど、意味が分かる名前を使うと保守しやすくなります。
dotnet newテンプレートでも、shortNameやidentityに一貫性を持たせることが大切です。
9-4. テンプレート化する前に重複コードを見極める
似ているコードがあるからといって、すぐにテンプレート化する必要はありません。
まずは、重複している部分と異なる部分を分けて考えましょう。
共通化することで読みやすくなるならテンプレート化し、逆に分かりにくくなるなら個別実装のままでも問題ありません。
9-5. チーム開発で使いやすいテンプレートにする
チームで使うテンプレートは、分かりやすさが重要です。
複雑な設定を必要とするテンプレートより、すぐに使えるテンプレートのほうが定着しやすいです。
また、生成されるコードがチームのコーディング規約に合っているかも確認しましょう。
9-6. READMEやサンプルコードを用意する
テンプレートを配布する場合は、READMEを用意しましょう。
インストール方法、使い方、生成例、注意点を書いておくと、チームメンバーが迷わず使えます。
特にdotnet newテンプレートでは、コマンド例を載せると親切です。
Bashdotnet new install ./MyTemplate
dotnet new custom-console -n SampleApp
9-7. バージョン管理しやすい構成にする
テンプレートは一度作って終わりではありません。
.NETのバージョン、ライブラリの更新、チーム規約の変更に合わせてメンテナンスが必要です。
Gitなどでバージョン管理し、変更履歴を残しておくと安心です。
10. C#テンプレートのよくある質問
最後に、C#テンプレートに関するよくある質問をまとめます。
10-1. C#にC++のtemplateはある?
C#にはC++のようなtemplateキーワードはありません。
C#で同じような役割を担うのはジェネリックです。
型を後から指定して共通処理を書きたい場合は、<T>を使ったジェネリックを学びましょう。
10-2. C#のtemplateとgenericの違いは?
C#では、C++のtemplateに近い機能がgenericです。
ただし、C#の「テンプレート」という言葉は広く使われます。
ジェネリック、Visual Studioテンプレート、dotnet newテンプレート、文字列テンプレート、Template Methodパターンなど、文脈によって意味が変わります。
10-3. ジェネリックとobject型は何が違う?
object型はどんな型でも扱えますが、型変換が必要になり、実行時エラーが起きる可能性があります。
ジェネリックは型を保ったまま処理できるため、コンパイル時に型チェックできます。
基本的には、型安全に再利用したいならジェネリックを使うべきです。
10-4. Visual Studioテンプレートとdotnet newテンプレートはどちらを使うべき?
Visual Studio中心で開発しているなら、Visual Studioテンプレートが使いやすいです。
CLI、チーム開発、複数OS、CI/CDで使いたいなら、dotnet newテンプレートがおすすめです。
迷った場合は、再利用範囲が広いdotnet newテンプレートから検討するとよいでしょう。
10-5. 既存プロジェクトをテンプレート化できる?
できます。
Visual Studioではプロジェクトテンプレートとしてエクスポートできます。
dotnet newテンプレートでも、既存プロジェクトに.template.config/template.jsonを追加することでテンプレート化できます。
ただし、binフォルダ、objフォルダ、ユーザー固有の設定ファイルなどは除外しましょう。
10-6. テンプレートをNuGetで配布できる?
dotnet newテンプレートはNuGetパッケージとして配布できます。
チーム内のプライベートNuGetフィードに置けば、標準プロジェクト構成を簡単に共有できます。
Bashdotnet new install Your.Template.Package
この形にしておくと、導入や更新がしやすくなります。
10-7. 初心者はどのC#テンプレートから学ぶべき?
初心者は、まずジェネリックから学ぶのがおすすめです。
List<T>、Dictionary<TKey, TValue>、ジェネリックメソッド、ジェネリッククラスを理解すると、C#のテンプレート的な考え方が身につきます。
その後、プロジェクト作成を効率化したい場合はdotnet newテンプレート、文字列生成を効率化したい場合は文字列テンプレートを学ぶとよいでしょう。
まとめ
C#テンプレートには、複数の意味があります。
型を汎用化するジェネリック、プロジェクトやファイルを作成するVisual Studioテンプレート、CLIで使えるdotnet newテンプレート、文字列やコードを生成する文字列テンプレート、設計パターンとしてのTemplate Methodパターンです。
csharp templateで調べている人が最初に理解すべきなのは、C#にはC++のようなtemplateキーワードはなく、型の再利用にはジェネリックを使うという点です。
実務では、ジェネリックで重複コードを減らし、Visual Studioやdotnet newテンプレートでプロジェクト作成を効率化し、文字列テンプレートでメールやHTMLを生成できます。
テンプレートは便利ですが、目的に合った方式を選ぶことが重要です。汎用化しすぎず、読みやすく保守しやすい形で使えば、C#開発の効率と品質を大きく高められます。

