Menu
Coddy logo textTech

ジェネリクス (クラスとメソッド)

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 42/70。

ジェネリクスを使用すると、型安全性を維持しながら、あらゆるデータ型で動作するクラスやメソッドを記述できます。IntListStringListDoubleList のために個別のクラスを作成する代わりに、それらすべてを処理する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>を作成すると、コンパイラはすべてのTintに置き換えます。これにより、コンパイル時の型チェックが提供され、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> のようなコレクションの基盤であり、再利用可能で型安全なコードを可能にします。

challenge icon

チャレンジ

簡単

あらゆる型のアイテムを保持および管理できる汎用的な 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)}

例えば、入力が 42100HelloWorld の場合、出力は以下のようになります:

Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: Hello

Storage<T> クラスを一度書くだけで、intstring の両方で完璧に動作することに注目してください。これがジェネリクスの魔法です!コンパイラが型安全性を保証するため、誤って整数ストレージに文字列を追加してしまうようなことはありません。

チートシート

ジェネリクスを使用すると、型安全性を維持しながら、任意のデータ型で動作するクラスやメソッドを記述できます。

ジェネリッククラスは、山括弧で囲まれた型パラメータ(通常は 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)}
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン