1. ホーム 
  2. 備忘録 
  3. C Sharp

ジェネリック

ジェネリック

ジェネリック(generics:総称性)あるいは総称的プログラミングとも呼ばれるが、この機能はさまざまな型に対応するために、型をパラメータとして与えて、その型に対応したクラスや関数を生成するものである

ジェネリックは型の部分を Type と定義することで使用できる

  • ジェネリック:型だけ違って処理の内容が同じようなものを作るときに使う
  • ジェネリッククラス:特定の機能を共通して持つさまざまな型のクラスを定義できる
  • ジェネリックメソッド:特定のメソッドをさまざまな型に対して実行できる

ジェネリックメソッド

例えば与えられた引数の中から最大値を求める Max 関数を作る場合、与えられる型が int型 なのか double型 なのか それ以外なのかわからない状況だと別々に関数を用意する必要がある

しかし、ジェネリックメソッドを用いると、必要に応じていろいろな型に対応した関数を生成できる

class Program
{
    static void Main()
    {
        int n1 = Max<int>( 5, 10 );   // int 版の Max を明示的に呼び出し
        int n2 = Max( 5, 10 );        // int 版の Max が自動的に生成される
        double x = Max( 5.0, 10.0 );    // double 版の Max が自動的に生成される
        string s = Max( "abc", "cat" ); // string 版の Max (辞書式順序で比較)
    }

    // C# のジェネリックを使うと比較などの演算子が使えなくなってしまう
    // これを回避するために CompareTo() を使用するが、このメソッドを使用できるようにするには、
    // 引数自身が『比較が可能(Comparable)』であることをメソッドに教えなければいけない
    public static Type Max<Type>( Type a, Type b ) where Type : IComparable
    {
        return a.CompareTo( b ) > 0 ? a : b;
    }
}

ジェネリッククラス

関数と同じく、クラスでもさまざまな型に対応したものを作成したいときがある

例えば、コレクションクラス(配列とかリストとかの、物の集まりのこと)などがその典型的な例である

// generics 版スタッククラス
// 説明用につきエラー制御などはなし
class Stack<Type>
{
  Type[] buf;
  int top;
  public int Size
  {
    get { return this.top; }
  }
  public int MaxSize
  {
    get { return this.buf.Length; }
  }

  public Stack(int max)
  {
    this.buf = new Type[max];
    this.top = 0;
  }

  public void Push(Type val)
  {
    this.buf[this.top++] = val;
  }

  public Type Pop()
  {
    return this.buf[--this.top];
  }
}

Stack<int>    si = new Stack<int>(SIZE);    // int型を格納できるスタックになる
Stack<double> sd = new Stack<double>(SIZE); // double型を格納できるスタックになる

where

where キーワードを使うことで、ジェネリッククラス・メソッドに指定した <型引数> の中の型が満たすべき条件を指定できる

// クラス
class クラス名<型引数>
  where 型引数中の型が満たすべき条件
{
  クラス定義
}

// メソッド
アクセスレベル 戻り値の型 メソッド名<型引数>(引数リスト)
  where 型引数中の型が満たすべき条件
{
  メソッド定義
}

条件(制約)の種類には以下のようなものがある

複数の制約を課したい場合は , で制約を並べることができる

制約 用途
where T : struct 型Tは「値型」である
where T : class 型Tは「参照型」である
where T : [base class] 型Tは[base class]で指定された型を継承する。
where T : [interface] 型Tは[interface]で指定されたインターフェースを実装する。
where T : new() 引数なしのコンストラクタを持つ。他の制約条件と同時に課す場合には、一番最後に指定する必要がある。
↓ C# 7.3で追加
where T : unmanaged 型Tは「アンマネージ型」である
where T : Enum 型Tは「列挙型」である
where T : Delegate 型Tは「デリゲート型」である
↓ C# 7.3で追加
where T : notnull 型Tには非 null な型しか渡せない

    参考文献

  1. [C# によるプログラミング入門]ジェネリック