講義メモ 後半

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

講義メモ

・p.204「静的クラス」から

p.204 静的クラス

・静的メンバのみによるクラスは、静的クラスにすることができる
・書式: static class クラス名 {…}
・義務はないが、静的クラスにしておくことで、誤って静的ではないメンバが出現することを防止できる

アレンジ演習:p.204 static02.cs

・静的クラスにインスタンスメンバを追記してエラーになることを確認しよう

作成例

//p.204 static02.cs C#2.0以降
using System;
static class MyClass { //静的クラス
    public static int x; //静的データメンバ
    // int y; //エラーになる
    public static void showX() { //静的メソッド
        System.Console.WriteLine("x = {0}", x);
    }
}
class static02 {
    public static void Main() {
        MyClass.x = 10; //静的データメンバなのでクラス名指定で扱う
        MyClass.showX(); //静的メソッドなのでクラス名指定で扱う
    }
}

p.205 静的メンバとインスタンスメンバの混在

・1クラスに静的メンバとインスタンスメンバの混在が可能だが、下記のルールがある
① 静的メソッドはインスタンス変数を扱えない(区別できないので)
② 静的メソッドはインスタンスメソッドを呼べない(〃)
③ 静的メソッドはthisを使えない(thisはインスタンスを指すので)
・なお、インスタンスメンバから静的メンバへのアクセスには制限はない(クラスに1つしかないので)

p.205 static03.cs 解説図

 

アレンジ演習:p.205 static03.cs

・静的メソッドでインスタンス変数を扱うとエラーになることを確認しよう
・静的メソッドでインスタンスメソッドを呼ぶとエラーになることを確認しよう
・静的メソッドでthisを使うとエラーになることを確認しよう

作成例

//アレンジ演習:p.205 static03.cs
using System;
class Cat {
    static int NoOfTail; //静的データメンバ
    string Name; //インスタンス変数
    public void SetName(string strName) { //インスタンスメソッド
        Name = strName; //インスタンス変数を扱える
    }
    public void ShowCat() { //インスタンスメソッド
        if (Name == null) { //インスタンス変数を扱える
            Console.WriteLine("名前が設定されていません");
            return;
        }
        Console.WriteLine("猫の名前は{0}で尾の数は{1}本です", Name, NoOfTail); //静的データメンバも扱える
    }
    public static void setCatTail(int no) { //静的メソッド
        //ここでインスタンスフィールドにアクセス不可
        //Name = "マイケル";
        NoOfTail = no; //静的データメンバは扱える
        //ShowCat(); //インスタンスメソッドを呼ぶとエラー
        //this.name = ""; //thisを使うとエラーになる
    }
} 
class static03 {
    public static void Main() {
        Cat.setCatTail(1);
        Cat mycat = new Cat();
        Cat yourcat = new Cat();
        mycat.ShowCat();
        mycat.SetName("マイケル");
        yourcat.SetName("パトリシア");
        mycat.ShowCat();
        yourcat.ShowCat();
    }
}

p.207 プロパティ

・メソッドに近い記述により、外部からは変数のように扱える仕掛がプロパティ。
 ※ データベースなどでは「属性」のことをプロパティというが、C#のプロパティは意味が異なる
・変数などを扱うプロパティを定義して、外部に利用を許可することで、外部からはプロパティがデータそのものに見える
・プロパティの中でデータの利用を制限したり、更新を不可にしたりできるので、データの安全性を高めることが可能
 例: 身長を表す変数に負の数を代入できるが、身長を扱うプロパティの中で負の数の代入を却下できる
・プロパティで扱う変数をprivate指定にし、プロパティをpublicにすると良い
・プロパティは1つのデータを受け渡すので、そのデータ型がプロパティの型になる
・プロパティにはgetとsetの2つのアクセッサ(アクセス記述)があり、どちらかは省略可能
・外部で、プロパティを利用するとgetの内容が、プロパティに代入するとsetの内容が実行される
・getの基本構文は「get { return 式や値; }」で、returnが必ず実行される必要がある
・setの基本構文は「set { 変数など = value; }」で、代入した値がvalueキーワード経由で渡される
 定義例(負の身長を排除できる): 
 private double height; //身長を直接操作することを禁止
 pubic double high { get { return height; } set { height = (value > 0) ? value : 0; } }

アレンジ演習:p.208 prop01.cs

・各アクセッサにコンソール出力を追記し、自動的に呼び出されていることを確認しよう

作成例

//p.208 prop01.cs
using System;
class MyClass {
    double bl; //直接利用できない=プロパティ経由で扱う
    public double blprop { //プロパティ(blの値を返すのでdouble型)
        get { //getアクセッサ(プロパティを利用すると呼ばれる)
            Console.WriteLine("getが呼ばれた"); //【追加】
            return bl; 
        }
        set { //setアクセッサ(プロパティに代入すると呼ばれる)
            Console.WriteLine("setが呼ばれた"); //【追加】
            bl = value; 
        } 
    }
}
class prop01 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.blprop = 165.2; //setアクセッサが呼ばれる
        Console.WriteLine("bl = {0}", mc.blprop); //getアクセッサが呼ばれる
    }
}

p.207 プロパティ:setアクセッサにおける不適切な代入の防止

・setアクセッサに条件を記述することで、代入できる値や相手を制限できる
・なお、setアクセッサを省略すると読み込み専用に、getアクセッサを省略すると閲覧不可にできる

アレンジ演習:p.209 prop02.cs

・どちらかのgetアクセッサを省略すると「設定はできるが閲覧ができない」となることを確認しょう

作成例

//アレンジ演習:p.209 prop02.cs
using System;
class BMI {
    double bw, bl;
    public double blprop { //プロパティ(身長用)
        //get { //削除可能
        //        return bl; //無条件で返す
        //}
        set {
            if (value <= 0) { //代入値が0以下なら
                Console.WriteLine("身長に0または負の値は設定できません");
                return; //何もしないで戻る
            }
            bl = value; //代入値を身長に代入
        }
    }
    public double bwprop { //プロパティ(体重用)
        //get { //削除可能
        //    return bw; //無条件で返す
        //}
        set {
            if (value <= 0) { //代入値が0以下なら
                Console.WriteLine("体重に0または負の値は設定できません");
                return; //何もしないで戻る
            }
            bw = value; //代入値を体重に代入
        }
    }
    public double CalcBMI() {
        if (bl == 0.0 || bw == 0.0) {
            Console.WriteLine("データがセットされていません");
            return 0.0;
        }
        return bw / Math.Pow(bl, 2.0); //BMIを計算して返す
    }
}
class prop02 {
    public static void Main() {
        BMI mybmi = new BMI();
        double bl, bw;
        do {
            Console.Write("身長(m)--- ");
            string strBl = Console.ReadLine();
            bl = double.Parse(strBl);
            mybmi.blprop = bl; //プロパティblpropのsetアクセッサを呼ぶ
        } while (bl <= 0.0);
        do {
            Console.Write("体重(kg)--- ");
            string strBw = Console.ReadLine();
            bw = double.Parse(strBw);
            mybmi.bwprop = bw; //プロパティbwpropのsetアクセッサを呼ぶ
        } while (bw <= 0.0);     
        //Console.WriteLine("bl = {0}, bw = {1}", 
        //    mybmi.blprop, mybmi.bwprop); //プロパティblpropとbwpropのgetアクセッサを呼べなくなるだけ
        Console.WriteLine("BMI = {0:#.#}", mybmi.CalcBMI());
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位は「龍が如く8 外伝 Pirates in Hawaii」GO!
賞金総額140万円!ゲーム開発コンテスト『Tokyo Game Jam』参加者募集。ゲーム制作へのAI活用や業界動向、ハッカソンのコツを語るプレイベント開催 GO!
Steamの日替わりセール対象が1日6枠に拡張!1年間で2,500本以上のゲームを支援した精選プロモーション GO!
電子書籍ストア運営のBookLive、PCゲーム市場に初参入 GO!
「現実のギャンブルルールではない」訴え認められ人気ローグライク『Balatro』『幸運の大家様』海外レーティング緩和へ GO!

「生成AI利用した作品のフィルタ」機能をSteamDBが実装―AI利用を開示した作品を一括で非表示に GO!
ワーナーが『Wonder Woman』開発を含む3スタジオを閉鎖…サ終迫る『MultiVersus』スタジオも継続せず GO!

前回のコメント

・本日もありがとうございました。
 また来週もお願いします。

 残り3回は少しペースが上がりますので、
 しっかりとスキルアップしてください。

・今回もありがとうございました。
 もうあと数回ですね、すごく早く感じます。
 次回もよろしくお願いします。

 こちらこそ、よろしくお願いいたします。

・本日もありがとうございました。
・今日もありがとうございました。次も頑張ります。

 応援します。

講義メモ 後半

p.201 引数が可変個のメソッド

・メソッドの引数にparamsキーワードと配列を指定することで、引数が可変個のメソッドになる
・よって、同型の引数をいくつでも指定できる1メソッドが記述できる
・書式: アクセス修飾子 戻り値型 メソッド名(params 配列型[] 仮引数) {…}
・メソッド内部では仮引数を配列として、各引数はその要素になる
・よって、引数の数は、仮引数.Lengthで得ると良い
・引数が0個でもかまわないが、要素数0の配列になるので、要素を使用すると異常終了する

アレンジ演習:p.201 params01.cs

・「if(animal1.Length == 0)」は不用なので消そう
・その後ろのfor文はforeachで書き換えよう
・Mainにおいて、引数が1個の場合、2個の場合を加えよう
・また、引数をint型にしたメソッドでオーバーロードできるが条件があることを確認しよう
 ⇒ 引数が0個である呼び出しをすると、両方にマッチしてしまうので、エラーになる

作成例

//p.201 params01.cs
using System;
class MyClass {
    public void show(params string[] animal) { //string型の可変個引数のメソッド
        foreach (var w in animal) { //全引数について繰返す
            Console.WriteLine("{0}さんがいます", w);
        }
    }
    public void show(params int[] animal) { //int型の可変個引数のメソッド
        foreach (var w in animal) { //全引数について繰返す
            Console.WriteLine("{0}です", w);
        }
    }
}
class params01
{
    public static void Main()
    {
        MyClass mc = new MyClass();
        //mc.show(); //showメソッドをオーバーロードにしたので区別不可でエラーになる
        mc.show("ぱんだ");
        mc.show("いぬ", "ねこ");
        mc.show("きりん", "ぞう", "かば");
        mc.show(100);
        mc.show(200, 300);
    }
}

ミニ演習:mini202.cs

・実数の可変個引数を受け取って、平均値を返す double ave(params double[]) を作成し、動作を確認しよう

作成例

//ミニ演習:mini202.cs
using System;
class MyClass {
    public double ave(params double[] val) { //double型の可変個引数のメソッド
        double sum = 0.0; //合計
        foreach (var w in val) { //全引数について繰返す
            sum += w; //合計に足し込む
        }
        return sum / val.Length; //平均値を返す
    }
}
class params01 {
    public static void Main() {
        MyClass mc = new MyClass();
        Console.WriteLine(" = {0}",              mc.ave());
        Console.WriteLine("1.1 = {0}",           mc.ave(1.1));
        Console.WriteLine("1.1, 2.2 = {0}",      mc.ave(1.1, 2.2));
        Console.WriteLine("1.1, 2.2, 3.3 = {0}", mc.ave(1.1, 2.2, 3.3));
    }
}

p.202 静的メンバ

・通常、クラスの各メンバはインスタンスに所属する
 例:Slimeクラスにhpを定義すると、Slimeクラスのインスタンスslalinに所属し、slalin.hpになる
・しかし、インスタンスに所属する必要がないような=クラスに所属するメンバも記述できる
・それが静的メンバで、staticを前置して示す
 例:Slimeクラスに「生成したスライム数」を持たせる場合、インスタンスには所属しないので、クラスで持つ方が良い
・また、インスタンス変数を全く用いないメソッドもクラスで持つ方が良く、これを静的メソッドという
・静的メンバはクラスに所属するので「クラス名.」を前に付けて実行する
・よって、静的メンバはインスタンスの生成をしなくても利用できる
・なお、Console.WriteLineは、Consoleクラスの静的メソッドなので「Console.」を前につけている
・また、Mathクラスのメンバの大半は静的メンバ(例:Math.PI)
・近い理由で、Mainメソッドも静的メソッドである必要があるので「static」を前置する
・逆に言えば、静的メンバはインスタンスごとにはならない特殊なものであり、オブジェクト指向のメリットを生かせないので乱用は避けること。
※ つまり、設計図に直接データを書き込んでいるようなイメージ

アレンジ演習:p.203 static01.cs

・変数xにMyClassのインスタンスの生成数を格納するようにして、動作を確認しよう
・生成はデフォルトコンストラクタでのみ行うとする

作成例

//p.203 static01.cs
using System;
class MyClass {
    public static int x; //静的データメンバ(インスタンス数)
    public static void showX() { //静的メソッド
        Console.WriteLine("x = {0}", x);
    }
    public MyClass() { //【追加】コンストラクタ
        x++; //静的データメンバをインクリメント
    }
}
class static01 {
    public static void Main() {
        MyClass.x = 0; //静的データメンバなので直接アクセスできる
        MyClass.showX(); //静的メソッドなので直接呼び出せる
        MyClass m1 = new MyClass(); //【追加】コンストラクタが呼ばれる
        MyClass.showX(); //静的メソッドなので直接呼び出せる
    }
}

作成例(発展形)

//p.203 static01.cs
using System;
class MyClass {
    public static int x; //静的データメンバ(インスタンス数)
    public static void showX() { //静的メソッド
        Console.WriteLine("x = {0}", x);
    }
    public int n; //【追加】自分は何番目かを示すインスタンス変数
    public MyClass() { //【追加】コンストラクタ
        x++; //静的データメンバをインクリメント
        n = x; //自分は何番目か
    }
    public void showN() { //【追加】インスタンスメソッド
        Console.WriteLine("ボクは{0}番目です", n);
    }
}
class static01 {
    public static void Main() {
        MyClass.x = 0; //静的データメンバなので直接アクセスできる
        MyClass.showX(); //静的メソッドなので直接呼び出せる
        MyClass m1 = new MyClass(); //コンストラクタが呼ばれる
        m1.showN(); //【追加】インスタンスメソッドで何番目かを表示
        MyClass m2 = new MyClass(); //コンストラクタが呼ばれる
        m2.showN(); //【追加】インスタンスメソッドで何番目かを表示
        MyClass m3 = new MyClass(); //コンストラクタが呼ばれる
        m3.showN(); //【追加】インスタンスメソッドで何番目かを表示
    }
}

提出:アレンジ演習:p.203 static01.cs

講義メモ

・p.195「メソッドのオーバーロード」から

提出:ミニ演習 mini193.cs・改

・アレンジ演習:p.191 changearray01.csを元に、引数のaとbの和をout waで、差をout saで、積をout seiで返すメソッドにしてみよう
 void modify(int a, int b, out int wa, out int sa, out int seki){…}

作成例

//ミニ演習 mini193.cs・改
using System;
class change {
    public void modify(int a, int b, out int wa, out int sa, out int seki) { //aとbの和差積を返すメソッド
        wa = a + b; //和を格納する 
        sa = (a > b) ? a - b : b - a; //差を格納する 
        seki = a * b; //積を格納する 
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        int x, y, z; //宣言のみで良い
        c.modify(10, 20, out x, out y, out z); //参照渡しで和差積を書きこんでもらう
        Console.WriteLine("{0}と{1}の和は{2},差は{3},積は{4}", 10, 20, x, y, z);
    }
}

p.195 メソッドのオーバーロード

・p.168のとおり、シグニチャ(引数の数、型、並び)が異なるコンストラクタを複数定義できることをオーバーロードという
・メソッドもオーバーロードが可能で、シグニチャが異なる同じ名前のメソッドを複数定義できる
・なお、メソッドのシグニチャには戻り値型は含まれないので、戻り値型のみが異なるメソッドの複数定義はできない
・これは呼び出し時に区別できないから
・なお、整数⇒実数のように暗黙の型変換により一致するオーバーロードがあれば、それが採用される
・メソッドのオーバーロードにより、同じ意味のメソッドは同じ名前にできる

アレンジ演習:p.195 overload01.cs

・第5のバージョンとして「Method(double x, double y)」を適当な内容で追加し、呼び出せることを確認しよう
・Mainメソッドで、m.Method(5.1, 6)を呼び出すと、暗黙の型変換によりこの第5のバージョンが動作することを確認しよう

作成例

//p.195 overload01.cs
using System;
class manymethods
{
    public int Method(int x) {
        Console.WriteLine("第1のバージョンが呼ばれました");
        return x + 10;
    }
    public double Method(double x) {
        Console.WriteLine("第2のバージョンが呼ばれました");
        return x * 2;
    }
    public string Method(string x) {
        Console.WriteLine("第3のバージョンが呼ばれました");
        return x += "です";
    }
    public int Method(int x, int y) {
        Console.WriteLine("第4のバージョンか呼ばれました");
        return x + y;
    }
    public double Method(double x, double y) { //【以下追加】
        Console.WriteLine("第5のバージョンか呼ばれました");
        return x + y;
    }
}
class overload01 {
    public static void Main() {
        manymethods m = new manymethods();
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3)); //第1のバージョンを呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3.2));  //第2のバージョンを呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method("粂井")); //第3のバージョンを呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5, 6)); //第4のバージョンを呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5.1, 6)); //【追加】第5のバージョンを呼ぶ
    }
}

p.197 Mainメソッドのオーバーロード

・Mainメソッドは特殊なメソッドであり、コンソールプログラム等の動作の始点になる
・通常、public static voidとし、引数は指定しないが、バリエーション(オーバーロード)がある。
・戻り値型をvoidからintにすると「return 整数値」が記述可能になり、このプログラムを呼び出した元に整数値を返すことができる
・なお、VisualStudioのデバッグ機能から呼び出した場合は、返される値は表示されないが、一般に、正常終了したら0を、
 でなければ0以外を返すことが多い
・Windowsではビルド済のプログラムをVisualStudioを介さずに実行し、戻り値を表示する方法がある(後述)
・また、引数にstring[]=文字列配列を指定すると、起動時に、システムから複数の文字列を渡すことができる
・この文字列をコマンドライン引数という
・VisualStudioでは、デバッグのプロパティでコマンドライン引数を指定できる
・Windowsではビルド済のプログラムをVisualStudioを介さずに実行し、実行時にコマンドライン引数を指定する方法がある(後述)

p.198 main01.cs:VisualStudioにおける実行方法

① ソースを記述する
②「デバッグ」「●のデバッグプロパティ」
③「コマンドライン引数」に「cat dog apple」と入力
④「ファイル」「すべて保存」
⑤「デバッグなしで開始」

p.198 main01.cs

//p.198 main01.cs
using System;
class main01 {
    public static int Main(string[] s) { //コマンドライン引数を受け取るMainメソッド
        int n;
        n = s.Length; //引数の数=配列の要素数を得る
        Console.WriteLine("引数の個数は{0}個です", n);
        if (n != 0) { //引数があれば(※このif文は実際は無用)
            for (int i = 0; i < n; i++) { //コマンドライン引数全てについて繰返す
                Console.WriteLine("引数{0} : {1}", i + 1, s[i]);
            }
        }
        return 0; //正常終了を返す
    }
}

p.198 main01.cs:開発者用コマンドプロンプトにおける実行方法

① ソースを記述し「ビルド」「ソリューションのビルド」(※既に実行済なら不用)
②「ツール」「コマンドライン」「開発者用コマンドプロンプト」
③「プロジェクト名\bin\debug\プロジェクト名 コマンドライン引数」を入力し、Enterで実行
例:Project1\bin\debug\Project1 cat dog apple
※ この時、②で表示される文字列をカレントディレクトリ(パス)という
例:F:\ha242_AkibaC#\Project1

p.198 main01.cs:通常のコマンドプロンプトにおける実行方法

① Windows10では「スタート」「Windowsシステムツール」「コマンドプロンプト」
  Windows11では「スタート」「すべてのアプリ」「Windowsツール」「コマンドプロンプト」
② カレントディレクトリ(パス)の先頭文字(ドライブレター)が「C」でなければ、ドライブレターと「:」を入力し、Enter
例:F:
③ カレントディレクトリ(パス)と「\」を入力し、続けて「プロジェクト名\bin\debug\プロジェクト名 コマンドライン引数」を入力し、
 Enterで実行
例:F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1 cat dog apple

p.199 main02.cs:通常のコマンドプロンプトで実行し戻り値を表示する方法

① Visual Studioでmain02.csのソースを記述し「ビルド」「ソリューションのビルド」
② Windows10では「スタート」「Windowsシステムツール」「コマンドプロンプト」
  Windows11では「スタート」「すべてのアプリ」「Windowsツール」「コマンドプロンプト」
③ カレントディレクトリ(パス)の先頭文字(ドライブレター)が「C」でなければ、ドライブレターと「:」を入力し、Enter
例:F:
④ カレントディレクトリ(パス)と「\」を入力し、続けて「プロジェクト名\bin\debug\プロジェクト名 コマンドライン引数」を入力し、
 Enterで実行
例:F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1 cat dog apple
⑤「echo %errorlevel%」と入力しEnterを押すと、戻り値が表示される

p.199 main02.cs

//p.199 main02.cs
using System;
class main02 {
    public static int Main(string[] args) { //コマンドライン引数を受け取り戻り値を返す
        if (args.Length != 1) { //コマンドライン引数が1個ではない?
            return -1; //-1を返す
        } else { //コマンドライン引数が1個?
            if (!Char.IsDigit(args[0][0])) { //第0要素の0文字目(引数の先頭文字)が数字以外?
                return -2; //-2を返す
            }
        }
        return int.Parse(args[0]); //第0要素を整数化して返す
    }
}

通常のコマンドプロンプトで実行し戻り値を表示する方法の例

F:\>F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1

F:\>echo %errorlevel%
-1

F:\>F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1 cat dog

F:\>echo %errorlevel%
-1

F:\>F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1 cat

F:\>echo %errorlevel%
-2

F:\>F:\ha242_AkibaC#\Project1\Project1\bin\debug\Project1 2100000000

F:\>echo %errorlevel%
2100000000

※ p.200のバッチファイルの説明は割愛します

今週の話題

ゲームソフト販売本数ランキング:今週1位は再び「ドンキーコング リターンズ HD(Switch)」 GO!
「東京ゲームショウ 2025」は9月25日開催―アクセシビリティコーナー新設、通路幅の拡大などの改善を発表 GO!
「高くても売れる」PS5 Pro効果でハード販売23%増―新CEOが描くソニーの”脱コングロマリット”戦略【ゲーム企業の決算を読む】GO!
AIでゲームシナリオを最短1営業日で生成、Algomaticが新サービス―130言語対応で海外展開も効率化 GO!
「消費者がSteamを使用する理由を過小評価していた…」Amazon元重役、Prime GamingがSteamに勝てなかった理由語る。重要な視点逃した結果の高すぎる勉強料 GO!

miHoYoのリーカー取り締まり続く。200人以上が対象、最高で約1,100万円に及ぶ賠償金も GO!

前回のコメント

・理解できた

 何よりです。

・今回もありがとうございました
 次回もよろしくお願いします。

 こちらこそ、よろしくお願いいたします。

・今日もありがとうございました。
 全然関係ないですが、先生の授業でプログラムの知識をたくさん教えてもらえていたので
 仕事で急遽VBスクリプトやマクロを読む事になったのですが、変数やメソッドなどの処理の流れがC#と似てて読むことができ、
 自分でもスラスラとプログラムの流れを掴めて無事問題が解決することができました。
 プログラムを少しでも読めるようになると成長した実感も沸いて、自分に自信がつきました。
 授業内容の理解は追いつかなくても、先生の授業はいつも楽しくて、ありがたいです。
 残り4回ですが、ご指導のほどよろしくお願いします。

 何よりです。残り4回、しっかりスキルアップしてください。