特集

C#&VBジェネリック超入門(前編)

ジェネリック・クラスで変わる
C#とVBのコレクション

デジタルアドバンテージ 遠藤 孝信
2006/02/11
Page1 Page2 Page3 Page4

ジェネリックを使った新しいコレクション:Listジェネリック・クラス

 .NET Framework 2.0のクラス・ライブラリには、ジェネリックの仕組みを使ったリストである「Listジェネリック・クラス」が導入されています。このクラスは、新しいSystem.Collections.Generic名前空間に含まれています。

 Listジェネリック・クラスは、

  • C#の場合: List<T>クラス
  • VBの場合: List(Of T)クラス

として表記されます。C#の場合の不等号(山カッコ)、VBの場合のOfキーワードや、クラス名なのにカッコを付ける書き方は、ジェネリックのためにそれぞれの言語で新しく導入された記述方法です。

 そして、大文字の「T」は型パラメータ(タイプ・パラメータ)と呼ばれるもので、インスタンスの作成時には「T」の部分にリストの要素として扱いたい型を指定して記述します。

 例えば、List<T>クラスを文字列(string型)のリストとしてインスタンス化し、要素を追加するには次のように記述します。

List<string> stringList = new List<string>();

stringList.Add("こんにちわ");
stringList.Add("さようなら");
Dim stringList As New List(Of String)

stringList.Add("こんにちわ")
stringList.Add("さようなら")
Addメソッドによる要素の追加(List)

 型パラメータに「string」を指定することにより、このリストは格納される要素をstring型として扱います。つまり、stringListオブジェクトは文字列専用のコレクションとなります。

 このため、Addメソッドはパラメータとしてstring型のみが指定可能となります。よって、以下のような記述はコンパイル時にエラーとなります。

Uri site = new Uri("http://www.atmarkit.co.jp");
stringList.Add(site); // コンパイル・エラー
Dim site As New Uri("http://www.atmarkit.co.jp")
stringList.Add(site) ' コンパイル・エラー
Addメソッドによる要素の追加(List)
stringListオブジェクトはstring型専用なので、ほかの型を追加しようとするとコンパイル・エラーとなる。

 コレクションに対する操作は、従来のArrayListクラスと同じようにして行えます。インデクサも用意されていて、この場合にはオブジェクトを取り出すのにキャストは不要です。これはインデクサがstring型を返すためです。

string greeting;
greeting = stringList[0]; // キャスト不要
Dim greeting As String
greeting = stringList(0) ' キャスト不要
インデクサによる要素の取り出し(List)
stringListオブジェクトはstring型専用なので、インデクサもstring型のオブジェクトを返す。

 もちろん、foreach文による順次処理もできます。この場合にもキャストは行われません。

foreach (string s in stringList) {
  Console.WriteLine(s);
}
For Each s As String In stringList
  Console.WriteLine(s)
Next
foreach文による要素の列挙(List)
ArrayListクラスで可能だったコレクションの基本的な操作はListジェネリック・クラスでも可能だ。

 Listジェネリック・クラスが追加されたことにより、ArrayListクラスを使うケースはほとんどなくなったといえるでしょう。

 以上のコードをまとめたコンパイル可能なソース・コードを以下に示しておきます。

using System;
using System.Collections.Generic;

class GenericSample {
  void Sample() {
    // List<T>クラスのインスタンス化
    List<string> stringList = new List<string>();

    // 要素の追加
    stringList.Add("こんにちわ");
    stringList.Add("さようなら");

    string greeting;
    greeting = stringList[0]; // キャスト不要

    Uri site = new Uri("http://www.atmarkit.co.jp");
    // stringList.Add(site); // コンパイル・エラー

    // 各要素の列挙
    foreach (string s in stringList) {
       Console.WriteLine(s);
    }
  }

  static void Main() {
    GenericSample gs = new GenericSample();
    gs.Sample();
  }
}
Imports System
Imports System.Collections.Generic

Class GenericSample
  Sub Sample()
    ' String(Of T)クラスのインスタンス化
    Dim stringList As New List(Of String)

    ' 要素の追加
    stringList.Add("こんにちわ")
    stringList.Add("さようなら")

    Dim greeting As String
    greeting = stringList(0) ' キャスト不要

    Dim site As New Uri("http://www.atmarkit.co.jp")
    ' stringList.Add(site) ' コンパイル・エラー

    ' 各要素の列挙
    For Each s As String In stringList
      Console.WriteLine(s)
    Next
  End Sub
End Class

Module Module1
  Sub Main()
    Dim gs As New GenericSample
    gs.Sample()
  End Sub
End Module
Listジェネリック・クラスを使用したサンプル・プログラム

【コラム】 値型のコレクションでも高速

 キャストが不要となる分、ジェネリックのコレクションは従来よりもパフォーマンスが上がりますが、コレクションで値型のオブジェクトを扱う場合にはさらに有用です。

 例えば、ArrayListオブジェクトに値型であるint型(Integer型)の数値を追加する場合、ArrayListクラス内部では数値をobject型に変換する際にボックス化(ボクシング)が行われます。これがパフォーマンスを劣化させる原因となります。

 しかし、Listジェネリック・クラスでint型を指定した場合、コレクションはint型専用となります。このためボックス化は行われません。

 次のサンプル・プログラムは、数値をArrayListオブジェクトに追加する場合と、ジェネリックのListオブジェクトに追加する場合の処理時間を計測します。

using System;
using System.Collections;
using System.Collections.Generic;

public class GenericSample {
  static void Main() {
    DateTime start, end;

    // ArrayListクラスを使った場合
    ArrayList alist = new ArrayList();
    start = DateTime.Now;
    for (int i = 0; i < 20000000; i++) {
      alist.Add(i);
    }
    end = DateTime.Now;

    Console.WriteLine(end - start);
    // 出力例:00:00:05.6875000

    // Listジェネリック・クラスを使った場合
    List<int> intList = new List<int>();
    start = DateTime.Now;
    for (int i = 0; i < 20000000; i++) {
      intList.Add(i);
    }
    end = DateTime.Now;

    Console.WriteLine(end - start);
    // 出力例:00:00:00.6718750
  }
}
Imports System
Imports System.Collections
Imports System.Collections.Generic

Module Module1
  Sub Main()
    Dim startTime, endTime As DateTime

    ' ArrayListクラスを使った場合
    Dim alist As New ArrayList
    startTime = DateTime.Now
    For i As Integer = 1 To 20000000
      alist.Add(i)
    Next
    endTime = DateTime.Now

    Console.WriteLine(endTime - startTime)
    ' 出力例:00:00:05.6406250

    ' Listジェネリック・クラスを使った場合
    Dim intList As New List(Of Integer)
    startTime = DateTime.Now
    For i As Integer = 1 To 20000000
      intList.Add(i)
    Next
    endTime = DateTime.Now

    Console.WriteLine(endTime - startTime)
    ' 出力例:00:00:00.8750000
  End Sub
End Module
値型オブジェクトの追加にかかる時間を計測するサンプル・プログラム
数値をArrayListオブジェクトに追加する場合と、ジェネリックのListオブジェクトに追加する場合の処理時間を計測する。

 コード内のコメント文に示したように、ジェネリックを使用したList<int>クラスの方が、ArrayListクラスに比べて、(筆者の環境の場合では)約6〜8倍高速になっているのが分かります。


 INDEX
  [特集]
  C#&VBジェネリック超入門(前編)
  ジェネリック・クラスで変わるC#とVBのコレクション
    1.従来のコレクションの代表:ArrayListクラス
  2.ジェネリックを使った新しいコレクション:Listジェネリック・クラス
    3.ジェネリック・クラスの記述方法
    4.Hashtableクラスを置き換えるDictionaryジェネリック・クラス
 
  C#&VBジェネリック超入門(後編)
  ジェネリックなメソッドやデリゲートがもたらす新スタイル
    1.ジェネリック・メソッド − ArrayクラスのIndexOfメソッド
    2.ジェネリック・デリゲート − Action<T>デリゲート
    3.Action<T>デリゲートを使用するList<T>クラスのForEachメソッド
    4.Comparison<T>デリゲートを使用するList<T>クラスのSortメソッド
 

TechTargetジャパン

Insider.NET フォーラム 新着記事
  • Kinectが切り開く“夢の近未来” (2012/2/2)
     日本を含めた世界中でKinect for Windowsセンサー商用版とSDK正式版がリリース。未来のコンピューティングはどう変化するのか?
  • 3つの視点でネイティブと.NETの適材適所を考察 (2012/1/31)
     アプリ開発は「ネイティブ」と「.NET」、どちらが最良? その問いには「適材適所」と答えるしかない。では、“適所”は一体どこかを考察する
  • SQL Azure Data Sync入門 (2012/1/30)
     SQL Azure/SQL Serverデータベース間のデータ同期を簡単に実現するサービスとは? その仕組みや使用手順を解説
  • Windows Phoneアプリ市場の現状を分析する (2012/1/27)
     Windows Phone のアプリ・ストアに日々登録されている多種多様なアプリ。カテゴリ別のアプリ数は? 市場の現状を明らかにする

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

キャリアアップ

.NET開発者中心に生まれ変わりました

.NET開発者中心コーナー

- PR -

@IT Sepcial

イベントカレンダー

PickUpイベント

- PR -
もっと見る
- PR -

お勧め求人情報

ホワイトペーパーTechTargetジャパン

@IT Sepcial
ソリューションFLASH