この新機能を使えばコレクション・クラスの利用が安全かつ効率的に! ちょっと難しいC# 2.0やVB 2005の「ジェネリック」を丁寧に解説。
Visual Studio 2005の登場に合わせてバージョンアップしたC# 2.0(以下、C#)やVisual Basic 2005(以下、VB)には、たくさんの新機能が導入されています。その中でもプログラマにとって今後欠かせない機能となるのは、やはり「ジェネリック」(Generics)です。
しかしC#やVBのビギナーにとって、ジェネリックは少々分かりづらい機能でもあります。本稿では2回にわたり、ジェネリックにより何ができるのか、どのように使うのかといったジェネリックの基本事項を分かりやすくまとめてみます。
ジェネリックとは、簡単にいうと、特定の型(クラス)に依存しないクラスやメソッドを記述するための仕組みです。この仕組みは、クラス、構造体、インターフェイス、メソッド、デリゲートに適用でき、ジェネリックの仕組みを使ったクラスやメソッドは、「ジェネリック・クラス」や「ジェネリック・メソッド」などと呼ばれます。
実際には、ジェネリックはコレクション(コレクション・クラス)を便利に利用/実装するための仕組みといえます。コレクションとは、複数のオブジェクトをまとめて管理するためのもので、代表的なものにリストやハッシュテーブルなどがあります(リストは配列と操作方法が似ていますが、配列がサイズ固定なのに対してリストはオブジェクトをいくつでも追加できます)。
Visual Studio 2005に含まれる.NET Framework 2.0のクラス・ライブラリには、このジェネリックの機能を使用して実装されたコレクションが多数追加されています。このため、それらの新しいコレクションを利用すれば、以前の1.xのころに比べて、プログラムをすっきりと効率的に記述できるようになっています。
まずは、.NET Framework 1.xで最もよく使用されたコレクションであろうで「ArrayListクラス」について簡単に振り返ってみます。
ArrayListクラスはSystem.Collections名前空間に分類されているクラスです。今後利用する機会は減っていくと思われますが、.NET Framework 2.0でももちろんArrayListクラスは利用可能です。
さて、ArrayListクラスでは、Addメソッドによりコレクションの要素となるオブジェクトを追加していきます(以降のコードでは上がC#、下がVBのコードとなっています)。
ArrayList alist = new ArrayList();
alist.Add("こんにちわ");
alist.Add("さようなら");
Dim alist As New ArrayList
alist.Add("こんにちわ")
alist.Add("さようなら")
コレクションに追加された要素は、インデクサにより取り出すことができます。しかしArrayListクラスの不便な点の1つは、取り出した要素を扱うのに、元の型にキャストする必要があることでした。
string greeting;
greeting = (string)alist[0]; // キャストが必要
Dim greeting As String
greeting = CType(alist(0), String) ' キャストが必要
これは、ArrayListクラスが内部で要素をObject型として取り扱っているためです。文字列型のオブジェクトを格納しても、それを取り出すときにはすべてObject型となってしまいます。これを元に戻すためにキャストが必要となります。
また、Objectクラスはすべてのクラスの基本クラスであるので、ArrayListクラスはどのような型のオブジェクトも格納できます。このため、ArrayListオブジェクトには、コレクションの要素として、ほかの型のオブジェクトも混ぜることができてしまいます。
Uri site = new Uri("http://www.atmarkit.co.jp");
alist.Add(site); // 要素としてUri型を追加
Dim site As New Uri("http://www.atmarkit.co.jp")
alist.Add(site) ' 要素としてUri型を追加
しかし、文字列ばかりを入れたつもりのコレクションに、なぜか誤ってこのようなUri型のオブジェクトを入れてしまうと*、それを取り出すときに、当然ながら文字列型へのキャストは失敗して実行時にエラーとなります。
* ここでUri型を使ったのには特に意味はありません。
// 実行時にキャストに失敗してエラー
greeting = (string)alist[2];
' 実行時にキャストに失敗してエラー
greeting = CType(alist(2), String)
コレクションのすべての要素を順番に処理する場合、foreach文(VBではFor Each文)を使うと便利ですが、関係のない型のオブジェクトが混ざっていると、同様に実行時にエラーとなってしまいます。
foreach (string s in alist) {
Console.WriteLine(s);
}
For Each s As String In alist
Console.WriteLine(s)
Next
以上のコードをまとめたコンパイル可能なソース・コードを以下に示しておきます。
using System;
using System.Collections;
class GenericSample {
void Sample() {
// ArrayListクラスのインスタンス化
ArrayList alist = new ArrayList();
// 要素の追加
alist.Add("こんにちわ");
alist.Add("さようなら");
string greeting;
// greeting = alist[0]; // コンパイル・エラー
greeting = (string)alist[0]; // キャストが必要
Uri site = new Uri("http://www.atmarkit.co.jp");
alist.Add(site); // 要素としてUri型を追加
// 実行時にキャストに失敗してエラー
greeting = (string)alist[2];
// 実行時に3つ目の要素でエラー
foreach (string s in alist) {
Console.WriteLine(s);
}
}
static void Main() {
GenericSample gs = new GenericSample();
gs.Sample();
}
}
Imports System
Imports System.Collections
Class GenericSample
Sub Sample()
' ArrayListクラスのインスタンス化
Dim alist As New ArrayList
' 要素の追加
alist.Add("こんにちわ")
alist.Add("さようなら")
Dim greeting As String
' greeting = alist(0) ' コンパイル・エラー
greeting = CType(alist(0), String) ' キャストが必要
Dim site As New Uri("http://www.atmarkit.co.jp")
alist.Add(site) ' 要素としてUri型を追加
' 実行時にキャストに失敗してエラー
greeting = CType(alist(2), String)
' 実行時に3つ目の要素でエラー
For Each s As String In alist
Console.WriteLine(s)
Next
End Sub
End Class
Module Module1
Sub Main()
Dim gs As New GenericSample
gs.Sample()
End Sub
End Module
次にジェネリック版ArrayListクラスである、Listジェネリック・クラスを見ていきます。
Copyright© Digital Advantage Corp. All Rights Reserved.