講義メモ 後半

p.212 インデクサ

・主に、配列をデータメンバとして持つクラスにおいて「オブジェクト名[添字]」とすることで要素を扱える仕組みがインデクサ
・アクセッサと似た記述が可能なので、データの保護にも役立つ
・定義書式: データ型 this[インデックス型 インデックス] { get {…} set {…} }
・getの基本構文は「get { return 配列名[インデックス]; }」
・setの基本構文は「set { 配列名[インデックス] = value; }」

アレンジ演習:p.213 indexer01.cs

・「""」が代入されたら要素に代入しないようにしよう

作成例

//アレンジ演習:p.213 indexer01.cs
using System;
class MyClass {
    string[] name = new string[5]; //データメンバである配列
    public string this[int i] { //インデクサの定義(データはstringで、インデックスはint)
        get {
            return name[i]; //インデックスを添字として配列の要素を得て返す
        }
        set {
            if (value != "") { name[i] = value; } //インデックスを添字として配列の要素に値を代入(""以外)
        }
    }
}
class indexer01 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc[0] = "一郎"; //オブジェクト名[インデックス]なので、インデクサのsetが呼ばれる
        mc[1] = "次郎";
        mc[2] = "三郎";
        mc[3] = "四郎";
        mc[4] = "五郎";
        mc[2] = ""; //インデクサのsetでチェックするので代入されない
        for (int i = 0; i < 5; i++) {
            Console.WriteLine(mc[i]); //オブジェクト名[インデックス]なので、インデクサのgetが呼ばれる
        }
    }
}

p.212 インデクサ:インデクサによるインデックスのチェック

・インデクサのsetおよびgetでインデックスの値をチェックできるので、範囲外の添字を指定したアクセスを安全に排除できる

アレンジ演習:p.214 indexer02.cs

・インデックスに負の数が与えられても異常終了しないようにインデクサで対処しよう

作成例

//p.214 indexer02.cs
using System;
class MyIndexer {
    int[] array; //配列の宣言のみ
    int nMax; //要素数
    public int this[int n] { //インデクサの定義(データはintで、インデックスはint)
        get {
            if (n < nMax && n >= 0) { //【変更】要素数よりインデックスが小さければ
                return array[n]; //インデックスを添字として用いて配列の要素値を返す
            } else {
                return 0; //でなければ0を返す
            }
        }
        set {
            if (n < nMax && n >= 0) { //【変更】要素数よりインデックスが小さければ
                array[n] = value; //インデックスを添字として用いて配列の要素に代入
            }
        }
    }
    public MyIndexer(int i) { //コンストラクタ(引数は要素数)
        array = new int[i]; //要素数の分の配列を定義する
        nMax = i; //引数を要素数とする
    }
}
class indexer02 {
    public static void Main() {
        MyIndexer mi = new MyIndexer(20); //20要素の配列を持つクラスオブジェクトを生成
        for (int i = 0; i < 20; i++) {
            mi[i] = i * i; //インデクサのsetを呼ぶ
        }
        for (int i = 0; i < 20; i++) {
            Console.WriteLine("{0} * {0} = {1}", i, mi[i]); //インデクサのgetを呼ぶ
        }
        //わざとに配列の範囲を超える
        mi[-30] = 30; //【変更】インデクサのsetで無視される
        Console.WriteLine("mi[-30] = {0}", mi[-30]); //【変更】インデクサのgetが0を返す
    }
}

p.212 文字列をインデックスとするインデクサ

・整数ではないインデックスを受け取ってインデクサの中で配列の要素にアクセスする処理を記述することができる
・よって、文字列をインデックスとするインデクサや、実数をインデックスとするインデクサも可能になる

アレンジ演習:p.217 indexer03.cs

・インデクサにsetがないので、setを呼ぶような処置を記述するとエラーになることを確認しよう

作成例

//p.217 indexer03.cs
using System;
class MyIndexer {
    string[] mon = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    public int this[string MonthName] { //インデクサの定義(データはintで、インデックスはstring)
        get {
            for (int i = 0; i < 12; i++) { //配列の全要素について繰返す
                if (MonthName == mon[i]) //インデックスと同値?
                    return i + 1; //添字+1を「月」として返す
            }
            return 0; //当てはまる要素がなければ「0月」として返す
        }
    }
}
class indexer03 {
    public static void Main() {
        MyIndexer mi = new MyIndexer();
        Console.WriteLine("Mayは{0}番目の月です", mi["May"]);
        Console.WriteLine("Decは{0}番目の月です", mi["Dec"]);
        Console.WriteLine("xは{0}番目の月です", mi["x"]);
        // mi["A"] = 5; //インデクサにsetがないのでエラーになる
    }
}

p.218 多次元のインデクサ

・2つ以上のインデクスを持つインデクサを記述できる
・2次元の書式: データ型 this[インデックス型① インデックス①, インデックス型② インデックス②] { get {…} set {…} }

アレンジ演習:p.219 indexer04.cs

・インデクサのgetにインデックスの範囲チェックを加えよう
・インデックスが不適切な時は""を返す

作成例

//アレンジ演習: p.219 indexer04.cs
using System;
class MyClass {
    string[,] name; //2次元配列の宣言のみ
    public string this[int i, int j] { //2次元のインデクサ(データはstringで、インデックスはint,int)
        get {
            if (i >= 0 && i < 2 && j >= 0 && j < 5) { //【追加】
                return name[i, j]; //2次元配列の該当する要素値を返す
            } else { //【以下追加】
                return "";
            }
        }
    }
    public MyClass() { //コンストラクタ
        name = new string[,]{ //2次元配列の初期化
            {"田中", "佐藤", "吉田", "加藤", "粂井"},{"工藤", "竹中", "斉藤", "太田", "杉本"}
        };
    }
}
class indexer04 {
    public static void Main() {
        MyClass mc = new MyClass();
        for (int i = 0; i < 2; i++) { 
            for (int j = 0; j < 5; j++) {
                Console.WriteLine("{0}組{1}番--{2}", i + 1, j + 1, mc[i, j]);
            }
        }
        Console.WriteLine("{0}組{1}番--{2}", 3, 12, mc[3, 12]); //異常終了せず、インデクサが""を返す
    }
}

p.220 インデクサのオーバーロード

・インデクサのシグニチャはインデックスのデータ型と数と並びであり、シグニチャの異なるインデクサを複数記述できる
・これをインデクサのオーバーロードという

アレンジ演習:p.220 indexer05.cs

・インデクサのgetにインデックスの範囲チェックを加えよう
・インデックスが不適切な時は0を返す
・データはintで、インデックスはdoubleであるインデクサを追記しよう
・インデクスの値をintにキャストして用いるものとする
・インデクスの値をintにキャストして、this[int]を呼ぶようにしよう

作成例

//アレンジ演習:p.220 indexer05.cs
using System;
class MyOverLoad {
    int[] a = new int[3] { 1, 2, 3 };
    int[,] b = new int[2, 2] { { 100, 200 }, { 300, 400 } };
    public int this[int i] { //インデクサ(データはintで、インデックスはint)
        get {
            if (i >= 0 && i < a.Length) { //【追加】
                return a[i];
            } else { //【以下追加】
                return 0; 
            }
        }
    }
    public int this[int i, int j] { //インデクサのオーバーロード(データはintで、インデックスはint,int)
        get {
            if (i >= 0 && i < 2 && j >= 0 && j < 2) { //【追加】
                return b[i, j];
            } else { //【以下追加】
                return 0; 
            }
        }
    }
    public int this[double i] { //インデクサのオーバーロード(データはintで、インデックスはdouble)
        get {
            return this[(int)i]; //インデックスをキャストしてインデクサthis[int]を呼ぶ
        }
    }
}
class indexer05 {
    public static void Main() {
        MyOverLoad mo = new MyOverLoad();
        for (int i = 0; i < 3; i++) {
            Console.WriteLine("mo[{0}] = {1}", i, mo[i]);
        }
        for (int i = 0; i < 2; i++) { 
            for (int j = 0; j < 2; j++) { 
                Console.WriteLine("mo[{0}, {1}] = {2}", i, j, mo[i, j]);
            }
        }
        Console.WriteLine("mo[-2] = {0}", mo[-2]);
        Console.WriteLine("mo[10, 2] = {0}", mo[10, 2]);
        Console.WriteLine("mo[3.14] = {0}", mo[3.14]);
    }
}

p.222 練習問題1 ヒント

・p.209 prop02.csを単純化すると良い
・double型のデータメンバ1つのみになる
・Mainメソッドで負の数や0を与えて動作を確認すること

p.222 練習問題2 ヒント

・p.217 indexer03.csをベースにすると良い
・コンストラクタで生徒数を入力する部分は、p.214 indexer02.csが参考になる
・生徒名を格納するstring型配列と、点数を格納するint型配列を宣言して用いると楽
 ※ 生徒名と点数をメンバとするクラスオブジェクトの配列にできればさらに良い
・要素の生成はコンストラクタで行うと良い
・Mainメソッドで格納結果を表示すること

提出:アレンジ演習:p.220 indexer05.cs

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です