ここからは配列について扱っていきます。本章では、配列がどのようなものなのか、そしてC#で「int[]」と書いたときに内部ではどのような型が生まれているのかを、1枚のスライドを使って整理します。具体的な宣言の仕方や使い方は次章以降で解説するので、ここでは配列の「正体」をつかむことを目標にします。
図1 タイトル画面「配列」
配列とは何か
配列とは、複数の値を1つの名前(変数名)でまとめて管理するデータ構造です。英語ではarray(アレイ)と呼びます。
図2 配列は複数の値を1つの名前でまとめて管理するデータ構造
たとえば3人分の点数を扱う場合、配列を使わなければscore1、score2、score3のように変数を3つ用意する必要があります。配列を使えば、scoresという1つの名前で3つの値をまとめて扱え、何番目の値かはインデックス(添字)で指定します。インデックスは0から始まる点に注意してください。
リスト1 変数を個別に用意する場合と配列を使う場合
// 配列を使わない場合:値の数だけ変数が必要 int score1 = 80; int score2 = 65; int score3 = 92; // 配列を使う場合:1つの名前でまとめて管理できる int[] scores = new int[3]; scores[0] = 80; // インデックスは0から始まる scores[1] = 65; scores[2] = 92;
C#では「型+[]」で配列になる
C#では、型の後ろに角括弧[]を付けて宣言すると、それが配列としての宣言になります。intであれば「int[]」、stringであれば「string[]」と書くだけです。
図3 C#では型+[]と記載すると配列になる
リスト2 型の後ろに[]を付けて配列を宣言する
int[] numbers; // intの配列 string[] names; // stringの配列 TextBox[] boxes; // クラス(TextBox)の配列も同じ書き方
CLR(ランタイム)が特殊な配列型を生成する
「int[]」と宣言すると、内部的にはCLR(ランタイム)が管理する特殊な配列型がint用として生成されます。私たちが「int[]」というクラスを自分で定義しているわけではなく、ランタイムが実行時に自動で用意してくれる型だということです。
図4 int[]と宣言するとCLRが管理する特殊な配列型がint用として生成される
そして、この特殊な配列型は、Arrayクラスの派生型として生成されます。
図5 特殊な配列型はArrayクラスの派生型として生成される
スライドの図で、この関係を確認しておきましょう。上にあるのがArrayクラスで、これは抽象クラスです。その下にあるのがint[]で、正式名はSystem.Int32[]です。int[]はArrayクラスのサブクラス(派生型)という位置づけで、CLRが実行時に自動生成します。
図6 Array(抽象クラス)とint[]の関係図
図7 int[]の正式名はSystem.Int32[]。CLRが実行時に自動生成する型
この関係は、実際にコードで確かめることができます。GetType()で配列の型を調べると正式名のSystem.Int32[]が得られ、さらにその基底クラス(BaseType)を調べるとSystem.Arrayになっています。
リスト3 int[]の正体を確認する
int[] numbers = new int[3]; Type t = numbers.GetType(); var result1 = t.FullName; // "System.Int32[]" var result2 = t.BaseType?.FullName; // "System.Array" var result3 = numbers is Array; // true var result4 = typeof(Array).IsAbstract; // true(Arrayは抽象クラス)
なお、Arrayクラスから派生できるのはランタイムとコンパイラだけです。開発者が自分でArrayクラスを継承したクラスを書くことはできず、配列を使いたいときは必ず言語が提供する「型+[]」の構文を使います。
リスト4 Arrayクラスを自分で継承することはできない
// コンパイルエラー CS0644
// 'MyArray' は特殊クラス 'Array' から派生できません
class MyArray : Array
{
}
Arrayクラスは配列操作に必要な機能を持っている
実際にコードを書くときは「int[]」と書くだけなので、Arrayクラスを特に意識する必要はありません。ただし、Arrayクラスには配列を操作するための機能が用意されています。
図8 Arrayクラスは配列操作に必要な機能を持っている
図の中のArrayクラスには、Length、IndexOf、Copyなどが記載されています。int[]はArrayクラスの派生型なので、これらの機能をそのまま使うことができます。
図9 ArrayクラスにはLength、IndexOf、Copyなどの機能がある
Lengthのようにインスタンスから直接使えるプロパティもあれば、IndexOfやCopyのように「Array.IndexOf(…)」「Array.Copy(…)」とArrayクラスの静的メソッドとして呼び出すものもあります。後者を使うときは、Arrayクラスの存在を意識しなければなりません。
リスト5 Arrayクラスの機能を使う例
int[] numbers = { 30, 10, 20 };
var result1 = numbers.Length; // 3(要素数)
var result2 = Array.IndexOf(numbers, 20); // 2(20が見つかった位置)
int[] copy = new int[3];
Array.Copy(numbers, copy, numbers.Length); // numbersの中身をcopyへコピー
Array.Sort(numbers); // { 10, 20, 30 } に並べ替え
これらの機能の詳しい使い方は、後続の「Arrayクラスの機能」や「Array.Copy」の章で扱います。
まとめ
図10 「配列とは」スライド全体
本章の内容を整理すると次のとおりです。配列は複数の値を1つの名前でまとめて管理するデータ構造で、C#では型の後ろに[]を付けて宣言します。「int[]」と書くと、CLRが実行時にint用の特殊な配列型(System.Int32[])を生成し、その型は抽象クラスであるArrayクラスの派生型になります。そのため、配列ではArrayクラスが持つLength、IndexOf、Copyなどの機能を使えます。
基本的には「型の後ろに角括弧を付けて宣言したら配列になる」と覚えておけば十分です。次章からは、配列の宣言の仕方や使い方を具体的なコードで見ていきます。
■非公開コース「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新機能」を観る