C# ジェネリクスの基本

ジェネリクス(Generics)は、型をパラメータ化する機能です。同じロジックを様々な型に対して再利用でき、型安全性を保ちながらコードの重複を減らせます。

ジェネリクスが解決する問題

ジェネリクスがない場合、異なる型に対して同じ処理を行うには、型ごとにコードを書くか、object 型を使う必要がありました。

// object を使う方法(型安全でない)
ArrayList list = new ArrayList();
list.Add(1);
list.Add("文字列"); // 異なる型も追加できてしまう

int value = (int)list[0]; // キャストが必要

object を使うと型チェックがコンパイル時に行われず、実行時エラーの原因になります。

ジェネリックコレクション

ジェネリクスを使った List<T> では、格納できる型が制限されます。

List&lt;int&gt; numbers = new List&lt;int&gt;();
numbers.Add(1);
numbers.Add(2);
// numbers.Add("文字列"); // コンパイルエラー!

int first = numbers[0]; // キャスト不要

<int> という型パラメータにより、int 型だけを格納するリストになります。

型安全性の確保

object を使う方法

どんな型でも格納可能。取り出し時にキャストが必要。実行時エラーの危険。

ジェネリクスを使う方法

指定した型のみ格納可能。キャスト不要。コンパイル時に型チェック。

様々なジェネリックコレクション

.NET には多くのジェネリックコレクションが用意されています。

List<T>

可変長の配列。最もよく使われるコレクション。

Dictionary<TKey, TValue>

キーと値のペアを格納。高速な検索が可能。

HashSet<T>

重複のない要素の集合。存在確認が高速。

Queue<T> / Stack<T>

先入れ先出し(FIFO)/ 後入れ先出し(LIFO)のコレクション。

// Dictionary の例
var scores = new Dictionary&lt;string, int&gt;();
scores["Alice"] = 95;
scores["Bob"] = 87;

Console.WriteLine(scores["Alice"]); // 95

// HashSet の例
var uniqueNumbers = new HashSet&lt;int&gt; { 1, 2, 3 };
uniqueNumbers.Add(2); // 重複は無視される
Console.WriteLine(uniqueNumbers.Count); // 3

ボックス化の回避

ジェネリクスは値型(int, struct など)を扱う際のボックス化も回避します。List<int> は内部的に int 型の配列を保持するため、object への変換(ボックス化)が発生しません。

// ArrayList:int が object にボックス化される
ArrayList arrayList = new ArrayList();
arrayList.Add(42); // ボックス化が発生

// List&lt;int&gt;:ボックス化なし
List&lt;int&gt; genericList = new List&lt;int&gt;();
genericList.Add(42); // そのまま int として格納

ジェネリクスは現代の C# プログラミングに欠かせない機能です。型安全性とパフォーマンスを両立させながら、再利用可能なコードを書くための基盤となっています。