コレクション【C#】

C#文法:コレクション:C02_List

ここからはList<T>を見ていきます。前回までに扱った配列とArrayListにはそれぞれ弱点がありました。List<T>はその両方の弱点を補ったコレクションで、現在のC#でもっともよく使われるものです。本章では、List<T>が登場した経緯を整理したうえで、生成・追加・件数の取得・インデックスによるアクセスという基本の使い方を確認します。

ボタンの追加

これまでと同じように、フォームに新しいボタンを1つ追加します。ボタンのTextは「List<T>」としておきます。

図1 今回のテーマはList<T>

図1 今回のテーマはList<T>

ArrayListのボタンの下に配置した「List<T>」ボタンをダブルクリックして、クリックイベントのハンドラーを生成します。

図2 「List<T>」ボタンを配置してダブルクリックする

図2 「List<T>」ボタンを配置してダブルクリックする

配列とArrayListの弱点

コードを書く前に、これまでの内容を振り返っておきます。配列は型安全ですが、要素数が固定のため要素の増減が面倒でした。一方のArrayListは要素の増減は簡単ですが、型安全ではありません。値を取り出すたびにキャストが必要になり、キャストに失敗すれば実行時エラーになる可能性もあります。プログラミングとしては非常に書きづらいやり方です。

このあたりのデメリットを補ったのがList<T>です。Visual Studio 2005、.NET Framework 2.0で型パラメータ(ジェネリック)が使えるようになり、それによってList<T>が使えるようになりました。この内容を、生成されたbutton14_Clickメソッドの中にコメントとして書いておきます。

private void button14_Click(object sender, EventArgs e)
{
    //List<T>
    //配列は型安全だが要素の増減が面倒
    //ArrayListは型安全でない
    //VS2005、.NET Framework 2.0で型パラメータ登場により
    //List<T>が使えるようになり、
    //この両者(配列,ArrayList)のデメリットを解消した
}

図3 List<T>が登場した経緯をコメントで整理する

図3 List<T>が登場した経緯をコメントで整理する

Visual Studio 2002や2003といった初期の時代、つまりC# 1.0の頃は、コレクションといえば配列とArrayListしかありませんでした。そのため、古いプログラムではArrayListで作られているものが多く見つかります。もし古いプログラムを見ていてArrayListが出てきたら、List<T>に置き換えていけばよい、と考えてください。

List<T>の生成

それではList<T>の使い方を見ていきます。List<T>はnewで生成し、山括弧(< >)の中に型を指定します。この山括弧の中に書く型が型パラメータです。

//型パラメータにより型安全
var list = new List<string>();

図4 山括弧に型を指定してList<T>を生成する

図4 山括弧に型を指定してList<T>を生成する

型パラメータを指定することで、型安全(タイプセーフ)になります。List<string>と書けば「このリストの中身はstringしか入っていない」という保証ができ、List<int>と書けば「intしか入っていない」という保証ができます。取り出すたびに型を気にしてキャストする必要がなくなるため、非常にプログラミングしやすくなります。

要素の追加

要素の追加や削除は、ArrayListと同じ感覚で行えます。Add、Remove、Clearといったメソッドが用意されています。ここではAddで3件追加します。

//型パラメータにより型安全
var list = new List<string>();
list.Add("AAA");
list.Add("BBB");
list.Add("CCC");
//ArrayListと同様の要素の増減が容易

図5 Addで要素を3件追加する

図5 Addで要素を3件追加する

ここまでのポイントは2つです。1つ目は、型パラメータにより型安全になっていること。2つ目は、ArrayListと同様に要素の増減が容易であることです。配列の「型安全」とArrayListの「増減のしやすさ」という、両者の良いところを併せ持っているわけです。

図6 ArrayListと同様に要素の増減が容易

図6 ArrayListと同様に要素の増減が容易

要素数はCountで取得する

要素の数を取得する方法は、配列とは異なります。配列ではLengthプロパティでしたが、List<T>ではCountプロパティを使います。List系のコレクションは基本的にCountになっている、と覚えておいてください。

//配列はLengthだが、ListはCountで件数
System.Diagnostics.Debug.WriteLine(list.Count + "件");

図7 Countプロパティで件数を出力する

図7 Countプロパティで件数を出力する

メソッドの末尾にブレークポイントを置いて実行し、「List<T>」ボタンを押します。出力ウィンドウを見ると「3件」と出力されており、Addした3件がそのまま件数として取得できていることがわかります。

図8 出力ウィンドウに「3件」と表示される

図8 出力ウィンドウに「3件」と表示される

list変数にマウスカーソルを合わせて中身を確認すると、Count = 3となっており、[0]に”AAA”、[1]に”BBB”、[2]に”CCC”の3つの要素が入っていることも確認できます。

図9 listの中に3つの要素が入っている

図9 listの中に3つの要素が入っている

インデックスによるアクセス

値へのアクセスも配列と同じです。角括弧にインデックスを指定してアクセスします。インデックスは0始まりなので、list[1]は2番目の要素を指します。ここでは2番目の要素を”XXX”に書き換えてみます。

list[1] = "XXX";

図10 インデックスを指定して要素にアクセスする

図10 インデックスを指定して要素にアクセスする

インテリセンスの表示を見ると、インデクサの型が「string List<string>[int index]」となっています。List<string>として生成したので、インデックスで取り出される要素の型もstringであることがコンパイル時点で確定しているわけです。

型安全であることの確認

では、stringのリストに対して数値を代入しようとするとどうなるでしょうか。次のように書いてみます。

list[1] = "XXX";
list[1] = 123;   // CS0029: 型 'int' を 'string' に暗黙的に変換できません

図11 stringのリストにintを入れようとするとコンパイルエラーになる

図11 stringのリストにintを入れようとするとコンパイルエラーになる

「型 ‘int’ を ‘string’ に暗黙的に変換できません」というコンパイルエラー(CS0029)になります。ArrayListでは何でも入れられてしまい、間違いに気づくのは実行時でしたが、List<T>では間違った型の値を入れようとした時点でコンパイルエラーになります。これが型安全ということです。確認ができたので、この行はコメントアウトしておきます。

list[1] = "XXX";
//list[1] = 123;//コンパイルエラーになるので型安全

もう一度実行してlistの中身を確認すると、[1]の値が”BBB”から”XXX”に変わっていることがわかります。

図12 [1]の値が"XXX"に変わっている

図12 [1]の値が”XXX”に変わっている

完成コード

本章で作成したコードの全体は次のとおりです。

private void button14_Click(object sender, EventArgs e)
{
    //List<T>
    //配列は型安全だが要素の増減が面倒
    //ArrayListは型安全でない
    //VS2005、.NET Framework 2.0で型パラメータ登場により
    //List<T>が使えるようになり、
    //この両者(配列,ArrayList)のデメリットを解消した

    //型パラメータにより型安全
    var list = new List<string>();
    list.Add("AAA");
    list.Add("BBB");
    list.Add("CCC");
    //ArrayListと同様の要素の増減が容易

    //配列はLengthだが、ListはCountで件数
    System.Diagnostics.Debug.WriteLine(list.Count + "件");

    list[1] = "XXX";
    //list[1] = 123;//コンパイルエラーになるので型安全
}

まとめ

List<T>は、型パラメータによって配列と同じ型安全性を持ちながら、ArrayListと同じように要素を簡単に増減できるコレクションです。要素数は配列のLengthではなくCountで取得し、要素へのアクセスは配列と同じく0始まりのインデックスで行います。以降の章では、このList<T>をさらに詳しく使っていきます。

C#文法:コレクション

■非公開コース「C#14新機能」プレゼント:
非公開コース「C#14新機能」(80分)をご覧になりたい方は
こちらからURLとパスワードを発行していますので、ご覧になってみてください。
非公開コース「C#14新機能」を観る

A01_はじめに
A02_プロジェクトの作成
B01_配列とは
B02_配列の生成とアクセス
B03_生成と同時に値を設定する
B04_型推論による生成
B05_メソッドの引数などにする場合の注意点
B06_Length
B07_IndexOfでの検索
B08_FindIndexでの検索
B09_Find
B10_Exists
B11_FindAllとFindLast
B12_誤ったコピー
B13_Array.Copy
B14_範囲指定のコピー
B15_Resize
C01_ArrayList
C02_List
C03_List 動的な要素の変更
C04_Listのコンストラクタ
C05_Listのコンストラクタ_Capacity
C06_ListTからArrayクラスのメソッドが呼ばれている
D01_コレクションインタフェースとは
D02_異なるコレクションクラスに互換性を持たせる
D03_インタフェースの階層構造
D04_クライアントができる操作を制限させる
D05_クライアントができる操作を制限させる_後半
D06_Enumerableの拡張メソッドに関して
D07_ReadOnly系のコレクションインタフェース
D08_AsReadOnly
D09_ToListでコピーする
D10_ListTはprivateで使う

■非公開コース「C#14新機能」プレゼント:
非公開コース「C#14新機能」(80分)をご覧になりたい方は
こちらからURLとパスワードを発行していますので、ご覧になってみてください。
非公開コース「C#14新機能」を観る