特集
» 2006年02月11日 00時00分 UPDATE

特集C#&VBジェネリック超入門(前編):ジェネリック・クラスで変わるC#とVBのコレクション (3/4)

[遠藤孝信,デジタルアドバンテージ]

ジェネリック・クラスの記述方法

 ここで簡単に、ジェネリック・クラスの記述方法についても見ておきましょう。

 以下は、Listジェネリック・クラスの仕様をまねたMyListジェネリック・クラスの実装例です。取りあえずAddメソッドとインデクサだけを実装しています。

public class MyList<T> {
  T[] _list = new T[1000]; // 要素は最大1000個まで
  int _size = 0;

  // Addメソッド
  public void Add(T item) {
    _list[_size++] = item;
  }

  // インデクサ
  public T this[int index] {
    get {
      return _list[index];
    }

    set {
      _list[index] = value;
    }
  }
}

Public Class MyList(Of T)
  Dim _list(1000) As T ' 要素は最大1000個まで
  Dim _size As Integer = 0

  ' Addメソッド
  Public Sub Add(ByVal item As T)
    _list(_size) = item
    _size += 1
  End Sub

  ' デフォルト・プロパティ(インデクサとして機能)
  Default Public Property Item(ByVal index As Integer) As T
    Get
      Return _list(index)
    End Get
    Set(ByVal value As T)
      _list(index) = value
    End Set
  End Property
End Class

ジェネリックを使用したMyListクラスの実装
格納する要素が1000を超えた場合にはエラーとなる。またインデクサでのインデックス番号の範囲チェックも行っていない。

 このように、ジェネリック・クラスの記述では、型パラメータを「T」とした場合、Tというクラスがあるかのようにフィールドやメソッドを記述していきます。

 これまでに「T」の部分が具体的なクラス名になっているようなクラスを記述されたことがあるかもしれません。例えば「T」の部分がすべて「Employee」になっているようなEmployeeクラス専用のコレクション・クラスなどです。

 ジェネリックの導入により、その「T」部分が自動的に置き換えられる、汎用的なコレクション・クラスが記述可能となったわけです。

 なお、型パラメータである「T」は単なるパラメータの名前であり、メソッドのパラメータと同じで、好きな名前を付けることができます。ただし名前付けのガイドラインは用意されています*。型パラメータが1つだけの場合は「T」がよく用いられます。

*「型パラメータの名前付けのガイドライン」を参照してください。


 念のために、上記のMyList<T>クラスを、文字列型とDateTime構造体で使用したサンプル・プログラムを次に示しておきます。

// MyList<T>クラスを利用

using System;

public class GenericSample {
  static void Main() {
    // 文字列用のリスト
    MyList<string> strings = new MyList<string>();

    strings.Add("こんにちわ");
    strings.Add("さようなら");

    string hello = strings[0];
    Console.WriteLine(hello);
    // 出力:こんにちわ

    // DateTime用のリスト
    MyList<DateTime> datetimes = new MyList<DateTime>();

    datetimes.Add(DateTime.Today);
    datetimes.Add(DateTime.MaxValue);

    DateTime today = datetimes[0];
    Console.WriteLine(today);
    // 出力例:2006/02/09 0:00:00
  }
}

' MyList(Of T)クラスを利用

Module Module1
  Sub Main()
    ' 文字列用のリスト
    Dim strings As New MyList(Of String)
    strings.Add("こんにちわ")
    strings.Add("さようなら")

    Dim greeting As String = strings(0)
    Console.WriteLine(greeting)
    ' 出力:こんにちわ

    ' DateTime用のリスト
    Dim datetimes As New MyList(Of DateTime)
    datetimes.Add(DateTime.Today)
    datetimes.Add(DateTime.MaxValue)

    Dim today As DateTime = datetimes(0)
    Console.WriteLine(today)
    ' 出力例:2006/02/09 0:00:00
  End Sub
End Module

MyListジェネリック・クラスを使用したサンプル・プログラム

【コラム】 型パラメータの制約

 ジェネリック・クラスを記述するとき、型パラメータに指定される型を制限する必要が出てくる場合があります。

 例えば、型パラメータの型(以下、Tと省略)のオブジェクトのメソッドを呼び出すようなコードを記述する場合、Tには必ずそのメソッドが実装されていなければ困ります。あるいは、Tのインスタンスを生成する(new T()する)ようなコードを記述する場合には、Tにパブリックな(パラメータを持たない)コンストラクタがなければ困ります。

 ジェネリック・クラスでこういった制約(constraints)を記述するには、C#ではwhereキーワード、VBでは「Of T」の後にAsキーワードを使います。

 以下に、記述可能な制約のパターンの一覧を実際のコードで示します(このコードはコンパイル可能です)。

class MyGenericClass1<T> where T : struct {
  // 制約:Tは構造体
}

class MyGenericClass2<T> where T : class {
  // 制約:Tはクラス
}

class MyGenericClass3<T> where T : new() {
  // 制約:Tはインスタンス化可能
}

class MyGenericClass4<T> where T : MyOtherClass {
  // 制約:TはMyOtherClassクラスを継承
}

class MyGenericClass5<T> where T : IMyInterface {
  // 制約:TはIMyInterfaceインターフェイスを実装
}

class MyGenericClass6<T, U> where T : U {
  // 制約:Tは別の型パラメータUを継承
}

//////////////////////////////////////////////////
class MyOtherClass {
  // とあるクラス
}

interface IMyInterface {
  // とあるインターフェイス
}

Class MyGenericClass1(Of T As Structure)
  ' 制約:Tは構造体
End Class

Class MyGenericClass2(Of T As Class)
  ' 制約:Tはクラス
End Class

Class MyGenericClass3(Of T As New)
  ' 制約:Tはインスタンス化可能
End Class

Class MyGenericClass4(Of T As MyOtherClass)
  ' 制約:TはMyOtherClassクラスを継承
End Class

Class MyGenericClass5(Of T As IMyInterface)
  ' 制約:TはIMyInterfaceインターフェイスを実装
End Class

Class MyGenericClass6(Of T As U, U)
  ' 制約:Tは別の型パラメータUを継承
End Class

''''''''''''''''''''''''''''''''''''''''''''''''''
Class MyOtherClass
  ' とあるクラス
End Class

Interface IMyInterface
  ' とあるインターフェイス
End Interface

記述可能な制約のパターンの一覧

 なおここでは説明は割愛しますが、1つの型パラメータに対して複数の制約を指定可能です。

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。