次の方法で共有


Visual Basic のジェネリック型 (Visual Basic)

ジェネリック型 は、複数のデータ型に対して同じ機能を実行するように適応する単一のプログラミング要素です。 ジェネリック クラスまたはプロシージャを定義する場合、その機能を実行するデータ型ごとに個別のバージョンを定義する必要はありません。

ドライバーセットは、取り外し可能なヘッドが付いているものに例えられます。 ネジを検査し、そのネジの正しいヘッド (スロット付き、クロス、星付き) を選択します。 ドライバー ハンドルに正しいヘッドを挿入したら、ドライバーとまったく同じ機能を実行します。つまり、ねじを回します。

異なる種類のヘッドを持つドライバーセットの図。

ジェネリック型を定義するときは、1 つ以上のデータ型を使用してパラメーター化します。 型パラメーターを使用すると、コードはその要件に合わせてデータ型を調整できます。 コードでは、ジェネリック要素から複数の異なるプログラミング要素を宣言できます。それぞれが異なるデータ型のセットに対して動作します。 ただし、宣言された要素はすべて、使用しているデータ型に関係なく、同じロジックを実行します。

たとえば、Stringなど、特定のデータ型を操作するキュー クラスを作成して使用できます。 次の例に示すように、System.Collections.Generic.Queue<T>からこのようなクラスを宣言できます。

Public stringQ As New System.Collections.Generic.Queue(Of String)

stringQ を使用して、String 値のみを操作できるようになりました。 stringQObject 値に対して一般化されるのではなく、String に固有であるため、遅延バインディングや型変換はありません。 ジェネリック型は実行時間を節約し、実行時エラーを減らします。

ジェネリック型の使用方法の詳細については、「方法: ジェネリック クラスを使用する」を参照してください。

ジェネリック クラスの例

次の例は、ジェネリック クラスのスケルトン定義を示しています。

Public Class classHolder(Of t)
    Public Sub processNewItem(ByVal newItem As t)
        Dim tempItem As t
        ' Insert code that processes an item of data type t.
    End Sub
End Class

上記のスケルトンでは、t型パラメーターです。つまり、クラスを宣言するときに指定するデータ型のプレースホルダーです。 コード内の他の場所では、tのさまざまなデータ型を指定することで、さまざまなバージョンの classHolder を宣言できます。 次の例は、このような 2 つの宣言を示しています。

Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)

上記のステートメントでは、構築されたクラスを宣言しています。このクラスでは、特定の型が型パラメーターを置き換えます。 この置換は、構築されたクラス内のコード全体に反映されます。 次の例は、integerClassprocessNewItem プロシージャがどのように表示されるかを示しています。

Public Sub processNewItem(ByVal newItem As Integer)
    Dim tempItem As Integer
    ' Inserted code now processes an Integer item.
End Sub

より完全な例については、「方法: 異なるデータ型で同一の機能を提供できるクラスを定義する」を参照してください。

対象となるプログラミング要素

ジェネリック クラス、構造体、インターフェイス、プロシージャ、およびデリゲートを定義して使用できます。 .NET では、一般的に使用されるジェネリック要素を表すジェネリック クラス、構造体、インターフェイスがいくつか定義されています。 System.Collections.Generic 名前空間は、ディクショナリ、リスト、キュー、スタックを提供します。 独自のジェネリック要素を定義する前に、System.Collections.Genericで既に使用できるかどうかを確認してください。

プロシージャは型ではありませんが、ジェネリック プロシージャを定義して使用できます。 Visual Basic のジェネリック プロシージャのを参照してください。

ジェネリック型の利点

ジェネリック型は、いくつかの異なるプログラミング要素を宣言するための基礎として機能し、それぞれが特定のデータ型で動作します。 ジェネリック型の代替手段は次のとおりです。

  1. Object データ型で動作する 1 つの型。
  2. 型の型固有のバージョンのセット。 各バージョンは個別にコーディングされ、StringInteger、またはユーザー定義型 (customerなど) などの 1 つの特定のデータ型で動作します。

ジェネリック型には、これらの代替方法よりも次の利点があります。

  • タイプ セーフ。 ジェネリック型では、コンパイル時の型チェックが適用されます。 Object に基づく型は任意のデータ型を受け入れ、入力データ型が許容できるかどうかを確認するコードを記述する必要があります。 ジェネリック型を使用すると、コンパイラは実行時前に型の不一致をキャッチできます。
  • パフォーマンス。 ジェネリック型はそれぞれが 1 つのデータ型に特化しているため、データのボックス化ボックス化解除を行う必要がありません。 Object に基づく操作では、入力データ型をボックス化して Object に変換し、出力用のデータのボックス化を解除する必要があります。 ボックス化とボックス化解除は、パフォーマンスを低下させます。 また、 Object に基づく型は遅延バインディングでもあります。つまり、この型のメンバーにアクセスするには、実行時に余分なコードが必要になります。 型変換により、パフォーマンスも低下します。
  • コード統合。 ジェネリック型のコードは、1 回だけ定義する必要があります。 型に固有のバージョンのセットでは、各バージョンで同じコードをレプリケートする必要があります。唯一の違いは、そのバージョンの特定のデータ型です。 ジェネリック型では、型固有のバージョンはすべて元のジェネリック型から生成されます。
  • コードの再利用。 特定のデータ型に依存しないコードは、ジェネリックである場合、さまざまなデータ型で再利用できます。 最初に予測しなかったデータ型でも、多くの場合、再利用できます。
  • IDE のサポート。 ジェネリック型から宣言された構築型を使用すると、コードの開発中に統合開発環境 (IDE) のサポートが向上します。 たとえば、IntelliSense では、コンストラクターまたはメソッドに対する引数の型固有のオプションを表示できます。
  • 汎用アルゴリズム。 型に依存しない抽象アルゴリズムは、ジェネリック型の候補として適しています。 たとえば、IComparable インターフェイスを使用して項目を並べ替えるジェネリック プロシージャは、IComparableを実装する任意のデータ型で使用できます。

制約

ジェネリック型定義のコードは可能な限り型に依存しない必要がありますが、ジェネリック型に提供される任意のデータ型の特定の機能が必要になる場合があります。 たとえば、並べ替えまたは照合する 2 つの項目を比較する場合、それらのデータ型は IComparable インターフェイスを実装する必要があります。 この要件を適用するには、型パラメーターに 制約 を追加します。

制約の例

次の例は、IComparableを実装するために型引数を必要とする制約を持つクラスのスケルトン定義を示しています。

Public Class itemManager(Of t As IComparable)
    ' Insert code that defines class members.
End Class

後続のコードが、IComparableを実装していない型を提供 itemManager からクラスを構築しようとすると、コンパイラはエラーを通知します。

制約の種類

制約では、次の要件を任意の組み合わせで指定できます。

  • 型引数は、1 つ以上のインターフェイスを実装する必要があります
  • 型引数は、最大で 1 つのクラスの型であるか、継承されている必要があります
  • 型引数は、そこからオブジェクトを作成するコードからアクセスできるパラメーターなしのコンストラクターを公開する必要があります
  • 型引数は、参照型である必要があります。または、値型である必要があります

C# コードでは、型引数がアンマネージ型である必要があることを宣言できます。 Visual Basic では、(C# で) この制約で定義されたジェネリック型またはメソッドを使用する Visual Basic コードに対して、この制約が適用されます。 ただし、Visual Basic の型パラメーターに対して unmanaged 制約を宣言することはできません。

複数の要件を適用する必要がある場合は、コンマ区切りの 制約リスト 中かっこ ({ }) を使用します。 アクセス可能なコンストラクターを要求するには、New Operator キーワードを一覧に含めます。 参照型を要求するには、Class キーワードを含めます。値型を必要とする場合は、Structure キーワードを含めます。

制約の詳細については、「型リストの」を参照してください。

複数の制約の例

次の例は、型パラメーターに制約リストを持つジェネリック クラスのスケルトン定義を示しています。 このクラスのインスタンスを作成するコードでは、型引数は、IComparable インターフェイスと IDisposable インターフェイスの両方を実装し、参照型であり、アクセス可能なパラメーターなしのコンストラクターを公開する必要があります。

Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
    ' Insert code that defines class members.
End Class

重要な用語

ジェネリック型では、次の用語が導入され、使用されます。

  • ジェネリック型。 宣言時に少なくとも 1 つのデータ型を指定するクラス、構造体、インターフェイス、プロシージャ、またはデリゲートの定義。
  • 型パラメーター. ジェネリック型定義では、型を宣言するときに指定するデータ型のプレースホルダー。
  • 型引数. ジェネリック型から構築された型を宣言するときに、型パラメーターを置き換える特定のデータ型。
  • 制約. 指定できる型引数を制限する型パラメーターの条件。 制約では、型引数に特定のインターフェイスの実装、特定のクラスからの継承、アクセス可能なパラメーターなしのコンストラクター、または参照型または値型を指定する必要があります。 これらの制約は組み合わせることができますが、最大で 1 つの基底クラスを指定できます。
  • 構築型。 型パラメーターの型引数を指定してジェネリック型から宣言されたクラス、構造体、インターフェイス、プロシージャ、またはデリゲート。

関連項目