C# ジェネリッククラスの定義
ジェネリッククラスを自分で定義することで、型に依存しない再利用可能なデータ構造やロジックを作成できます。
基本的な定義方法
クラス名の後に <T> を付けることで、型パラメータを持つクラスになります。
public class Box<T>
{
private T _content;
public void Put(T item)
{
_content = item;
}
public T Get()
{
return _content;
}
}T は型パラメータで、クラスを使う時に具体的な型に置き換わります。
ジェネリッククラスの使用
// int 型を格納する Box
var intBox = new Box<int>();
intBox.Put(42);
int number = intBox.Get(); // 42
// string 型を格納する Box
var stringBox = new Box<string>();
stringBox.Put("Hello");
string message = stringBox.Get(); // "Hello"同じ Box クラスが、int 用にも string 用にも使えています。
複数の型パラメータ
型パラメータは複数持つことができます。
public class Pair<TFirst, TSecond>
{
public TFirst First { get; set; }
public TSecond Second { get; set; }
public Pair(TFirst first, TSecond second)
{
First = first;
Second = second;
}
}var pair = new Pair<string, int>("Age", 25);
Console.WriteLine($"{pair.First}: {pair.Second}"); // Age: 25実用的な例:スタックの実装
ジェネリッククラスの実用例として、簡単なスタックを実装してみます。
public class SimpleStack<T>
{
private List<T> _items = new List<T>();
public void Push(T item)
{
_items.Add(item);
}
public T Pop()
{
if (_items.Count == 0)
throw new InvalidOperationException("スタックが空です");
T item = _items[_items.Count - 1];
_items.RemoveAt(_items.Count - 1);
return item;
}
public int Count => _items.Count;
}var stack = new SimpleStack<string>();
stack.Push("A");
stack.Push("B");
stack.Push("C");
Console.WriteLine(stack.Pop()); // C
Console.WriteLine(stack.Pop()); // B型パラメータの命名規則
型パラメータには慣習的な命名規則があります。
T
単一の型パラメータに使う汎用的な名前。
TKey, TValue
Dictionary のようにキーと値を扱う場合。
TInput, TOutput
入力と出力を区別する場合。
TElement
コレクションの要素型を表す場合。
型パラメータ名は大文字の T で始めるのが一般的です。説明的な名前を付けることで、コードの意図が伝わりやすくなります。
public class Repository<TEntity>
{
public void Save(TEntity entity) { /* ... */ }
public TEntity FindById(int id) { /* ... */ return default!; }
}ジェネリッククラスを活用することで、型安全かつ再利用可能なコンポーネントを設計できます。