ジェネリクス (クラスとメソッド)
CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 42/70。
ジェネリクスを使用すると、型安全性を維持しながら、あらゆるデータ型で動作するクラスやメソッドを記述できます。IntList、StringList、DoubleList のために個別のクラスを作成する代わりに、それらすべてを処理する1つの汎用的なクラスを記述します。
ジェネリッククラスは、通常山括弧で囲まれた T という名前の型パラメータを使用します:
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}
// 異なる型での使用
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");Box<int>を作成すると、コンパイラはすべてのTをintに置き換えます。これにより、コンパイル時の型チェックが提供され、int型のボックスに誤って文字列を格納することはできなくなります。
ジェネリックメソッドも同様に動作し、単一のメソッドが異なる型に対して動作することを可能にします。
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // x=2, y=1コンパイラは引数から型を推論するため、明示的に Swap<int> と記述する必要はありません。ジェネリクスは List<T> や Dictionary<TKey, TValue> のようなコレクションの基盤であり、再利用可能で型安全なコードを可能にします。
チャレンジ
簡単あらゆる型のアイテムを保持および管理できる汎用的な Storage<T> システムを構築しましょう。ジェネリクスの力を示す、再利用可能なコンテナクラスを作成します。一度書けば、整数、文字列、またはその他の任意の型で使用できます!
コードは2つのファイルに分けて構成します:
Storage.cs:DataStorage名前空間内にジェネリックなStorage<T>クラスを作成します。このストレージコンテナは以下の機能を備えている必要があります:- アイテムを保持するための型
Tのプライベート配列と、格納されているアイテムの数を追跡するCountプロパティを持つ - コンストラクタで容量を受け取り、内部配列を初期化する
- 空きがある場合にアイテムを追加する
Add(T item)メソッドを持つ - 指定されたインデックスにあるアイテムを返す
Get(int index)メソッドを持つ - 格納されているすべてのアイテムを
", "で結合して返すGetAll()メソッドを持つ
- アイテムを保持するための型
Program.cs: メインファイルで、ジェネリッククラスが2つの異なる型で動作することを実証します。Storage<int>とStorage<string>を作成し、それぞれにアイテムを追加して、同じクラスが両方の型でシームレスに動作することを示してください。
4つの入力を受け取ります:
- 保存する1つ目の整数
- 保存する2つ目の整数
- 保存する1つ目の文字列
- 保存する2つ目の文字列
容量5の整数ストレージと容量5の文字列ストレージを作成します。2つの整数を整数ストレージに、2つの文字列を文字列ストレージに追加してください。
出力は以下の形式で表示してください:
Int storage: {GetAll()}
Int count: {Count}
First int: {Get(0)}
String storage: {GetAll()}
String count: {Count}
First string: {Get(0)}例えば、入力が 42、100、Hello、World の場合、出力は以下のようになります:
Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: HelloStorage<T> クラスを一度書くだけで、int と string の両方で完璧に動作することに注目してください。これがジェネリクスの魔法です!コンパイラが型安全性を保証するため、誤って整数ストレージに文字列を追加してしまうようなことはありません。
チートシート
ジェネリクスを使用すると、型安全性を維持しながら、任意のデータ型で動作するクラスやメソッドを記述できます。
ジェネリッククラスは、山括弧で囲まれた型パラメータ(通常は T)を使用します。
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}インスタンスを作成するときに、T を置き換える型を指定します。
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");ジェネリックメソッドを使用すると、単一のメソッドで異なる型を操作できます。
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // コンパイラが引数から型を推論しますジェネリクスはコンパイル時の型チェックを提供し、List<T> や Dictionary<TKey, TValue> などのコレクションの基盤となっています。
自分で試してみよう
using System;
using DataStorage;
class Program
{
public static void Main(string[] args)
{
// 入力を読み込む
int num1 = Convert.ToInt32(Console.ReadLine());
int num2 = Convert.ToInt32(Console.ReadLine());
string str1 = Console.ReadLine();
string str2 = Console.ReadLine();
// TODO: 容量 5 の Storage<int> を作成する
// TODO: 2 つの整数を integer storage に追加する
// TODO: 容量 5 の Storage<string> を作成する
// TODO: 2 つの文字列を string storage に追加する
// TODO: 必要な形式で出力を表示する
// Int storage: {GetAll()}
// Int count: {Count}
// First int: {Get(0)}
// String storage: {GetAll()}
// String count: {Count}
// First string: {Get(0)}
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
5ポリモーフィズムとインターフェース
コンパイル時 vs 実行時ポリモーフィズムインターフェース vs 抽象クラス複数のインターフェース明示的なインターフェースアップキャストとダウンキャストまとめ - 図形計算機8オブジェクト指向の高度な概念
継承よりコンポジションジェネリクス (クラスとメソッド)デリゲートとイベント属性とリフレクションIDisposable と using ステートメント依存性の注入 (DI) の基礎