今週の話題

販売本数ランキング 今回トップは「ペルソナ3 リロード(PS5)」GO!
ドット絵によるアニメーション制作の味方『Aseprite』がSteamなどで50%オフの1025円に(2/14まで)。入門~本格的なゲーム制作まで幅広く活用可能 GO!
『GTA5』累計販売本数が1億9,500万本を突破―『GTA6』トレイラーや12月のアップデートでプレイヤーが増加傾向など決算報告で明らかに GO!
ゲームオーディオのグローバルリーダーAudiokinetic主催「Wwise Tour 2023 Tokyo」イベントレポート&『Hi-Fi RUSH』を手掛けたTango Gameworksインタビュー GO!
ネクソン、過去最高売上も業績予想には届かず―『THE FINALS』は“課金額が予想を上回る”好調スタート、日本では『ブルアカ』が成長 GO!
『The Elder Scrolls II: Daggerfall』有志Unity移植版の制作者が独自作品の開発に着手 GO!
KADOKAWA、アクワイアを100%子会社化―フロム・ソフトウェア、スパイク・チュンソフトとの連携を推進 GO!
ニンテンドースイッチの国内販売台数がニンテンドーDSを超える…気になる次世代機については言及避ける GO!
『ファンパレ』『FF7EC』『プロセカ』のエンジニア・クリエイターが登壇―サイバーエージェント主催の技術カンファレンス3/7開催 GO!
【決算】コロプラの第1四半期は2割の減収、4億1400万の営業赤字で着地 GO!
Unity Japan、大前広樹氏が社長を退任し、再びゲーム開発へ―新社長には産業営業本部長 松本靖麿氏 GO!

『原神』チートツール開発者に対し「可能な限り最高規模の」代償を、カナダで5万ドル規模以上の訴訟が進行中か―海外メディア報道 GO!

講義メモ 後半

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

・1つのクラスに静的メンバとインスタンスメンバを混在させることが可能
・ただし、静的メソッドはインスタンスメンバにアクセスできないので、下記は不可
 ① 静的メソッドの中でインスタンス変数を用いる
 ② 静的メソッドからインスタンスメソッドを呼び出す
・また、静的メソッドでは自オブジェクトを示すthisは使えない

p.205 static03.cs

//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; //静的変数に代入
    }
}
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 プロパティ

・データメンバへの値の設定や、データメンバからの値の読み出しは、データメンバをpublicにすれば自由にできるが、
 不適切な値の設定や、想定されていない読み出しがされることが避けられない。
・そこで、データメンバをprivate等に設定し、値の設定や値の読み出しは、メソッド経由にすることをカプセル化(p.4、p.166)という
・この場合に用いる値の設定や値の読み出し用のメソッドをアクセッサともいう
・アクセッサの記述に適した特別なメソッドの記述法がプロパティで、引数を持たず変数と同様に利用できる
・定義書式: public 型 プロパティ名 { get {…; return 値や式;} set {…;} }
 ※ 型は扱いたいデータメンバに合わせる
 ※ getの中においてデータメンバの値を返す
 ※ setの中では外部から与えられる値をvalueキーワードで得ることができ、通常、これをデータメンバに代入
・基本的な定義書式: public 型 プロパティ名 { get {return 変数名;} set {変数名 = value;} }
・代入式の左辺にプロパティを指定すると、setの内容が実行される。例:プロパティ名 = 値;
・代入式の左辺以外にプロパティを指定すると、getの内容が実行される。例:Console.Write(プロパティ名);
・getとsetのどちらかを省略可能で、setを省略することで外部からの値の設定を禁止(読み込み専用に)できる
・プロパティで不適切な値の設定を防ぐには、setにおいて値のチェックを行えば良い
 例: public double BH { set { if(value > 0) Height = value; } } //身長は正の数のみ設定可能

p.208 prop01.cs

//p.208 prop01.cs
using System;
class MyClass {
    double bl; //非公開のインスタンス変数
    public double blprop { //インスタンス変数bl用のプロパティ
        get { return bl; } //値の読み出し(「return 」)
        set { bl = value; } //値の設定で、「blprop = 値や式」とすると呼び出される
    }
}
class prop01 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.blprop = 165.2; //プロパティのsetを呼び出す
        Console.WriteLine("bl = {0}", mc.blprop); //プロパティのgetを呼び出す
    }
}

p.209 prop02.cs

//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;
        } while (bl <= 0.0); //身長に0以下の値が入力されている間繰返す=抜けない
        do { //繰返し開始
            Console.Write("体重(kg)--- ");
            string strBw = Console.ReadLine();
            bw = double.Parse(strBw);
            mybmi.bwprop = bw;
        } while (bw <= 0.0); //体重に0以下の値が入力されている間繰返す=抜けない
        Console.WriteLine("bl = {0}, bw = {1}", 
            mybmi.blprop, mybmi.bwprop); //プロパティで身長と体重を得て表示
        Console.WriteLine("BMI = {0:#.#}", mybmi.CalcBMI());
    }
}

p.211(静的プロパティ)

・静的データメンバのみを扱うプロパティは静的プロパティにすると良い
・すると「クラス名.プロパティ名」で扱うことが可能になる
・ただし、静的プロパティはインスタンスメンバにアクセスできないので、下記は不可
 ① 静的プロパティの中でインスタンス変数を用いる
 ② 静的プロパティからインスタンスメソッドを呼び出す

p.211 prop03.cs

//p.211 prop03.cs
using System;
class Test {
    static int x; //静的データメンバ
    public static int myprop { //静的プロパティ
        get { return x; }
        set { x = value; }
    }
}
class prop03 {
    public static void Main() {
        Test.myprop = 10; //静的プロパティ(クラス名.プロパティ名)を用いて値を代入
        Console.WriteLine("Test.myprop = {0}", Test.myprop); //静的プロパティを用いて値を得る
    }
}

p.212 インデクサ

・主にデータメンバである配列等をプロパティと同様に扱う仕掛けがインデクサ
・プロパティとは異なり、インデクサには名前がなく「インスタンスの参照変数[添字]」の形式で、配列の要素を扱える
・定義書式: public 型 this[インデックス型 インデックス] { get {…; return 値や式;} set {…;} }
 ※ 型は扱いたい配列等に合わせる
 ※ getの中において配列等の要素[インデックス]の値を返す
 ※ setの中では外部から与えられる値をvalueキーワードで得ることができ、通常、これを要素[インデックス]に代入
・基本的な定義書式: public 型 this[int i] { get {return 配列名[i];} set {配列名[i] = value;} }
・代入式の左辺に参照変数[添字]を指定すると、setの内容が実行される。例:参照変数[0] = 値;
・代入式の左辺以外に参照変数[添字]を指定すると、getの内容が実行される。例:Console.Write(参照変数[0]);

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

講義メモ

・p.201「引数が可変個のメソッド」から

提出フォロー: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 {
            if (!Char.IsDigit(args[0][0])) { //引数の0個目の0文字目が数字でなければ
                return -2;  //終了コード-12を返す(異常終了)
            }
        }
        return int.Parse(args[0]); //引数の0個目を整数化して終了コードとして返す
    }
}

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

・paramsキーワードと配列を引数として渡すことで、引数が可変個のメソッドが実現できる
・定義書式: アクセス修飾子 戻り値型 メソッド(params 引数型[] 引数名){…}
・引数の数に制限はないが、全てが同じ型、または、引数型のクラスの派生クラス型であること
・例: public int addall(params int[] n){…}
・ここの引数は引数名[添字]で利用可能で、指定された引数の数は、Lengthプロパティで得られる。

p.201 params01.cs

//p.201 params01.cs
using System;
class MyClass {
    public void show(params string[] animal) { //引数が可変個のメソッド
        if (animal.Length == 0) { //引数が全く指定されていなければ
            return; //何せずに戻る
        }
        for (int i = 0; i < animal.Length; i++) { //引数の数だけ繰返す
            Console.WriteLine("{0}さんがいます", animal[i]);
        }
    }
}
class params01 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.show(); //引数が全く指定せずに呼ぶ
        mc.show("きりん", "ぞう", "かば"); //引数を3つ指定して呼ぶ
    }
}

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

・for文は前判定繰り返しなので「引数が全く指定されていなければ」の判断は不要
・また、引数の数だけ繰返すにはforeachを用いると、Lengthプロパティを用いる必要はない
・以上を試そう

作成例

//アレンジ演習:p.201 params01.cs
using System;
class MyClass {
    public void show(params string[] animal) { //引数が可変個のメソッド
        foreach (var w in animal) { //全引数の分、繰返す
            Console.WriteLine("{0}さんがいます", w);
        }
    }
}
class params01 {
    public static void Main() {
        MyClass mc = new MyClass();
        mc.show(); //引数を全く指定せずに呼ぶ
        mc.show("きりん", "ぞう", "かば"); //引数を3つ指定して呼ぶ
    }
}

補足:引数が可変個のメソッド

・paramsの前に、通常の引数を定義できる。型が異なってもかまわない。
 例: public void show(int i, params string[] animal) {…}
・paramsの前に、通常の引数を複数定義できる。型が異なってもかまわない。
 例: public void show(int i, double d, params string[] animal) {…}
・通常の引数は省略できないので注意
 例: public void show(int i, params string[] animal) {…} の場合、呼び出しは
 「show(整数)」または「show(整数, 文字列,…,文字列)」である必要がある
・paramsは末尾の引数である必要があり、1つしか定義できない
・引数が可変個のメソッドもオーバーロード可能だが、確実に呼び分けができることが必要
・よって、引数がparamsのみのメソッドを複数記述すると、引数なしでの呼び出しはエラーになる
 例: public void show(params string[] animal) {…} と、
    public void show(params double[] animal) {…} がある場合、show()とするとエラー
・また、paramsの前に、paramsと同じ型の通常の引数を持つメソッドを記述すると、エラーにはならないが、paramsのみを持つメソッドは、
 引数なしの場合だけ呼び出される
 例: public void show(params string[] animal) {①} と、
    public void show(string s, params string[] animal) {②} がある場合、エラーにはならないが、
    show(文字列,…)とすると常に②が呼ばれ、show()とした場合にのみ①が呼ばれる

p.202 静的メンバ

・通常のインスタンス変数、メソッドなどのメンバは、クラスから生成したオブジェクトに含まれる
・よって、オブジェクトを指す参照変数を用いて「参照変数名.メンバ名」で用いる
・しかし、ConsoleクラスのWriteメソッドのように「Console.Write」と「クラス名.メンバ名」で利用できるものもあり、
 これはメンバがクラスに含まれている(特殊型)
・この、クラスに含まれているメンバを静的メンバといい、オブジェクトに含まれる必要が無い特別な場合に利用できるが、
 利用には制限がある
・静的データメンバの定義書式: アクセス修飾子 static 型 変数名;
・静的メソッドの定義書式: アクセス修飾子 static 戻り値型 メソッド名(){…};

p.203 static01.cs

//p.203 static01.cs
using System;
class MyClass {
    public static int x; //静的データメンバ
    public static void showX() { //静的メソッド
        Console.WriteLine("x = {0}", x);
    }
}
class static01 {
    public static void Main() {
        MyClass.x = 10; //インスタンスを生成せずに「クラス名.メンバ名」で利用可
        MyClass.showX(); //インスタンスを生成せずに「クラス名.メソッド名()」で利用可
    }
}

p.204 静的クラス

・全てのメンバが静的であるクラスは、静的クラスとしておくことで、将来、誤って静的ではないメンバが書き加えられたり、
 静的メンバがインスタンスメンバに書き換えられたりすることを防止できる。

p.204 static02.cs

//p.204 static02.cs
using System;
static class MyClass { //静的クラス
    public static int x; //静的データメンバ
    public static void showX() { //静的メソッド
        Console.WriteLine("x = {0}", x);
    }
}
class static01 {
    public static void Main() {
        MyClass.x = 10; //インスタンスを生成せずに「クラス名.メンバ名」で利用可
        MyClass.showX(); //インスタンスを生成せずに「クラス名.メソッド名()」で利用可
        Console.WriteLine(MyClass.X);
    }
}

今週の話題

販売本数ランキング 今回トップは「龍が如く8(PS5)」GO!
『アトリエ』シリーズ好調でコーエーテクモが2割増収―“月商20億円のスマートフォンゲーム”を生み出すことに成功【ゲーム企業の決算を読む】GO!
業績好調でも脱・中古ゲーム販売を進めるゲオが向かう先【ゲーム企業の決算を読む】GO!
『原神』が40カ月で売上50億ドルを達成―『クラッシュ・オブ・クラン』を抜き、モバイルゲーム最速記録 GO!
CESA、「CEDEC2024」開催を発表ーセッション講演者の公募を開始 GO!
マイクロソフトが2024年第2四半期決算を発表―アクティビジョン買収でゲーム部門が躍進 GO!
『いけにえと雪のセツナ』『鬼ノ哭ク邦』のTokyo RPG Factoryがスクエニに吸収合併、解散へ―権利義務一切はスクエニ側に引き継ぎ GO!
【決算】カプコンの3Q連結業績は4割超増益で着地―『スト6』などデジタル販売強化が奏功 GO!
【決算】コーエーテクモHDの3Q決算、経常利益100%増の大幅増益 GO!

AppleがEU圏でアプリのサイドローディングを許可するも大手アプリは反発―Xboxサラ・ボンド氏「間違った方向に進んでいる」GO!

講義メモ 後半

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

・p.168で説明のとおり、引数の型や数が異なるコンストラクタを記述できることをオーバーロード
・これは、メソッドでも可能なので、同じ意味の処理を行うメソッドは同じ名前にすると良い
 ※ オーバーロードができないC言語では関数名が長くなるというデメリットがある
・コンストラクタと同様にシグニチャが異なればOKだが、メソッドの戻り値型はシグニチャに含まれないので注意
・これは戻り値型だけが異なるメソッドは呼び出し時に区別できないため

p.195 overload01.cs

//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;
    }
}
class overload01 {
    public static void Main() {
        manymethods m = new manymethods();
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3)); //①を呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3.2)); //②を呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method("粂井")); //③を呼ぶ
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5, 6)); //④を呼ぶ
    }
}

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

・下記のシグニチャを持ち、最大値を返すMaxメソッドのオーバーロードに書き換えよう
① int Max(int, int)
② int Max(int, int, int)
③ double Max(double, double, double, double)
④ double Max(double[])

作成例

//アレンジ演習:p.195 overload01.cs
using System;
class manyMaxs {
    public int Max(int x, int y) { //メソッド①
        return (x > y) ? x : y; //大きい方を返す
    }
    public int Max(int x, int y, int z) { //メソッド②
        return (x > y) ? ((x > z) ? x: z) : ((y > z) ? y : z); //最大値を返す
    }
    public double Max(double x, double y, double z, double w) { //メソッド③
        double max1 = (x > y) ? x : y; //xとyの大きい方を得る
        double max2 = (z > w) ? z : w; //zとwの大きい方を得る
        return (max1 > max2) ? max1 : max2; //上記2者の大きい方を返す
 
    }
    public double Max(double[] d) { //メソッド④
        double max = double.MinValue;
        foreach (var w in d) { //全要素について作業変数wに取り出しながら繰返す
            if (w > max) {
                max = w; //最大値更新
            }
        }
        return max;
    }
}
class overload01 {
    public static void Main() {
        manyMaxs m = new manyMaxs();
        Console.WriteLine("max(3, 5):{0}", m.Max(3, 5)); //①を呼ぶ
        Console.WriteLine("max(3, 7, 1):{0}", m.Max(3, 7, 1)); //②を呼ぶ
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1):{0}", m.Max(3.14, 5.25, 7.79, -2.1)); //③を呼ぶ
        double[] da = {3.14, 5.25, 7.79, -2.1, 9.25};
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1, 9.25):{0}", m.Max(da)); //④を呼ぶ
    }
}

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

・最大値を求める処理を1つにしよう
・①②③の引数をdouble型の配列に格納して④を呼ぶと良い

作成例

//アレンジ演習:p.195 overload01.cs
using System;
class manyMaxs {
    public int Max(int x, int y) { //メソッド①
        double[] wa = {x, y}; //引数を配列化する
        return (int)Max(wa); //メソッド④を呼ぶ
    }
    public int Max(int x, int y, int z) { //メソッド②
        double[] wa = {x, y, z}; //引数を配列化する
        return (int)Max(wa); //メソッド④を呼ぶ
    }
    public double Max(double x, double y, double z, double w) { //メソッド③
        double[] wa = {x, y, z, w}; //引数を配列化する
        return Max(wa); //メソッド④を呼ぶ 
    }
    public double Max(double[] d) { //メソッド④
        double max = double.MinValue;
        foreach (var w in d) { //全要素について作業変数wに取り出しながら繰返す
            if (w > max) {
                max = w; //最大値更新
            }
        }
        return max;
    }
}
class overload01 {
    public static void Main() {
        manyMaxs m = new manyMaxs();
        Console.WriteLine("max(3, 5):{0}", m.Max(3, 5)); //①を呼ぶ
        Console.WriteLine("max(3, 7, 1):{0}", m.Max(3, 7, 1)); //②を呼ぶ
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1):{0}", m.Max(3.14, 5.25, 7.79, -2.1)); //③を呼ぶ
        double[] da = {3.14, 5.25, 7.79, -2.1, 9.25};
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1, 9.25):{0}", m.Max(da)); //④を呼ぶ
    }
}

別解(メソッド①②③の中身を1行に)

//アレンジ演習:p.195 overload01.cs
using System;
class manyMaxs {
    public int Max(int x, int y) { //メソッド①
        return (int)Max(new double[]{x, y}); //メソッド④を呼ぶ
    }
    public int Max(int x, int y, int z) { //メソッド②
        return (int)Max(new double[]{x, y, z}); //メソッド④を呼ぶ
    }
    public double Max(double x, double y, double z, double w) { //メソッド③
        return Max(new double[]{x, y, z, w}); //メソッド④を呼ぶ
    }
    public double Max(double[] d) { //メソッド④
        double max = double.MinValue;
        foreach (var w in d) { //全要素について作業変数wに取り出しながら繰返す
            if (w > max) {
                max = w; //最大値更新
            }
        }
        return max;
    }
}
class overload01 {
    public static void Main() {
        manyMaxs m = new manyMaxs();
        Console.WriteLine("max(3, 5):{0}", m.Max(3, 5)); //①を呼ぶ
        Console.WriteLine("max(3, 7, 1):{0}", m.Max(3, 7, 1)); //②を呼ぶ
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1):{0}", m.Max(3.14, 5.25, 7.79, -2.1)); //③を呼ぶ
        double[] da = {3.14, 5.25, 7.79, -2.1, 9.25};
        Console.WriteLine("max(3.14, 5.25, 7.79, -2.1, 9.25):{0}", m.Max(da)); //④を呼ぶ
    }
}

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

・Mainメソッドは特殊なメソッドであり、プログラムの動作開始位置の指定を行う
・Mainメソッドはpublic staticであり、戻り値はvoidまたはint、引数は無しまたは文字列配列であれば良い
・戻り値をintにすると、プログラムの呼び出し側に整数値を返すことができる
・プログラムの呼び出し側がOSの場合は正常終了した0を、でなければ0以外をreturnすると良い
・この値はシステム変数「errorlebel」で参照できるので、直後にコマンド「echo %errorlebel%」を実行すると得られる
・引数を文字列配列にすると、呼び出し時に0個以上の文字列を与えることができ、メソッド内で受け取って利用できる
・この文字列をコマンドライン引数といい、Visual Studioではデバッグのプロパティで指定可能
・コマンドプロンプトなどの外部処理からプログラムを実行可能であり、この時はプログラム名に続けてコマンドライン引数を指定可能
・なお、コマンドライン引数の数は不定なので、Lengthプロパティで要素数を得て用いると良い

p.198 main01.cs

//p.198 main01.cs
using System;
class main01 {
    public static int Main(string[] s) { //コマンドライン引数を受け取り整数を返す
        int n;
        n = s.Length; //コマンドライン引数の数を得る
        Console.WriteLine("引数の個数は{0}個です", n);
        if (n != 0) { //コマンドライン引数が指定されている?
            for (int i = 0; i < n; i++) { //全引数について繰返す
                Console.WriteLine("引数{0} : {1}", i + 1, s[i]);
            }
        }
        return 0; //正常終了を返す
    }
}

補足:コマンドラインからの実行方法

①「ツール」「コマンドライン」「開発者用コマンドプロンプト」
② cd プロジェクト名\bin\debug(例: cd chap8\bin\debug)
③ プロジェクト名に続けてコマンドライン引数を記述する(例: chap8 cat dog apple)
※ この環境では「\」が「/」の反対(バックスラッシュ)になるが同じ文字コードなので問題ない

p.200(バッチファイル)

・複数のコマンドをまとめて実行したい場合に、これらを記述して「●.bat」として保存するとバッチファイルとみなされる
・コマンドプロンプトでバッチファイル名をそのまま記述するだけで、内容が実行される

補足:バッチファイルの作成例

・開発者用コマンドプロンプトを起動して「notepad a.bat」「はい」でバッチファイルが作成可能になる
・下記を記述して「ファイル」「保存」して閉じる

ver
dir
date

・「a.bat」と入力すると、バージョン情報、ファイル一覧、日付確認の順に動作する
 ※日付確認はEnterキーを押すだけでOK

p.199 main02.csの実行方法

p.199「main02.cs」は、p.200のバッチファイル「main02test.bat」で実行する
①「main02.cs」は「デバッグなしで実行」は行わず「ビルド」「ソリューションのビルド」のみを行い、実行可能にしておく
②「ツール」「コマンドライン」「開発者用コマンドプロンプト」
③ cd プロジェクト名\bin\debug(例: cd chap8\bin\debug)
④ notepad main02test.bat
⑤ p.200のバッチファイル「main02test.bat」の内容をコピーペースト
⑥ この中の「main02」を全てプロジェクト名に書き換える
⑦「ファイル」「名前をつけて保存」して閉じる(このときエンコードを「ANSI」に変更すること)
⑧ main02test.bat

p.200のバッチファイル「main02test.bat」

@rem main02test.bat
@echo off
main02
echo %errorlevel%
echo 「main02.exe」の呼び出し結果です
main02
echo %errorlevel%
echo 「main02.exe」の呼び出し結果です
main02 a
echo %errorlevel%
echo 「main02.exe a」の呼び出し結果です
main02 20 30
echo %errorlevel%
echo 「main02.exe 20 30」の呼び出し結果です
main02 30
echo %errorlevel%
echo 「main02.exe 30」の呼び出し結果です

提出:p.199 main02.cs

講義メモ

・p.185「フィボナッチ数列を求める」から

p.181 階乗を計算する(再掲載)

・階乗とは、ある正の整数において、その数から1までの全整数の積
 ※ 実質的にはその数から2までの全整数の積になる
・整数nの階乗を「n!」で表し、例えば、2!は2、3!は6、4!は24、5!は120、…
・これを逆順で展開すると
 5! = 5×4×3×2×1
 4! =    4×3×2×1
 3! =       3×2×1
・なので、5!=5×4!、4!=4×3! であることから「n! = n×(n-1)!」が導ける。
・これをメソッドFactにすると、
 int CalcFact(int n) { //nの階乗
  return n * CalcFact(n - 1); //n×(n-1)!を返す(再帰する)
 }
・これに、再帰の終了条件として「0の階乗は1」を加えると良い
 int CalcFact(int n) { //nの階乗
  return (n > 0) ? n * CalcFact(n - 1) : 1; //nが0超ならn×(n-1)!を返す(再帰する)でなければ1を返す
 }
・p.182 fact01.csは上記を展開したメソッドになっている

提出フォロー:アレンジ演習:p.182 fact01.cs

・CalcFact(int n)メソッドを上記を用いてシンプルにしよう

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact {
    public long CalcFact(int n) { //n!を返す
        return (n > 0) ? n * CalcFact(n - 1) : 1; //nが0超ならn×(n-1)!を返す(再帰する)でなければ1を返す
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) {
            Console.WriteLine("{0}! = {1}", i, f.CalcFact(i));
        }
    }
}

p.185 フィボナッチ数列を求める

・フィボナッチ数列は統計やシミュレーションなどに用いる増加速度をもつ数字の並び。
・先頭2値が1で、それ以降は前2値の和になる
・実例: 1,1,2,3,5,8,13,21,34,55,…
・よって、n番目のフィボナッチ数はn-1番目とn-2番目の和として、再帰で表現できる

p.185 fibonacci.cs

//p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) { //フィボナッチ数列のn番目を返す
        long fb;
        if (n == 1 || n == 2) { //先頭2要素は1固定(再帰の終了条件でもある)
            fb = 1;
        } else {
            fb = CalcFibo(n - 1) + CalcFibo(n - 2); //3値目以降は前2値の和
        }
        return fb;
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

アレンジ演習:p.185 fibonacci.cs

・条件演算子を用いて記述をシンプルにしよう

作成例

//アレンジ演習:p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) { //フィボナッチ数列のn番目を返す
        return  (n == 1 || n == 2) ? 1 : CalcFibo(n - 1) + CalcFibo(n - 2); //3値目以降は前2値の和
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

p.188 refとout(値渡しと参照渡し)

・C#においてメソッドの引数は値渡しが基本であり、値のコピーが行われる
・よって、メソッド内で引数を変更しても、呼び出し側の指定した引数の値は変わらない
・p.189 swap01.csが失敗例で、Mainメソッドで定義して引数に指定しているxとyは、Swap関数の仮引数xとyとは(たとえ同名でも)無関係
・C/C++では参照型の場合に参照渡しによりこれを解決できるが、C#では参照型でも値渡しになる
・なお、配列などのようにデータ構造を渡した場合は、構造の占有位置を示す値が値渡しされるので、受け取った側で同じオブジェクトを
 用いるため、参照渡しになる

p.191 charngearray01.cs

//p.191 charngearray01.cs
using System;
class change {
    public void modify(int[] array) { //引数が配列なので実質的に参照渡し
        int n = array.Length; //要素数を得て
        for (int i = 0; i < n; i++) { //全要素について繰返す
            array[i] *= 2; //要素値を2倍にする
        }
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        int[] myarray = new int[3]{1, 2, 3};
        Console.WriteLine("----modifyメソッド実行前----");
        int i = 0;
        foreach (int x in myarray) { //配列myarrayの全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x); //値を表示
            i++;
        }
        c.modify(myarray); //要素値を2倍にする
        Console.WriteLine("----modifyメソッド実行後----");
        i = 0;
        foreach (int x in myarray) { //配列myarrayの全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++;
        }
    }
}

p.192 refキーワード

・値渡しとなる引数と仮引数の両方に「ref」を前置すると、参照渡しに変更される
・なお、この引数は事前に初期化が必要だが、変数名は同じである必要はない

p.193 swap03.cs

//p.193 swap03.cs
using System;
class myclass {
    private int temp;
    public void swap(ref int x, ref int y) { //仮引数xとyは参照渡しにする
        temp = x;
        x = y;    //ここでxを書き換えた結果が引数に反映する
        y = temp; //ここでyを書き換えた結果が引数に反映する
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int x = 10, y = 20;  //引数用の変数を初期化
        s.swap(ref x, ref y); //参照渡しにより、呼び出す
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}

p.194(outキーワード)

※ テキストではrefの代わりに無条件にoutが利用できるような説明になっているが、制限もある
・refに代わりにoutを指定すると、事前の初期化が不要になる
・ただし、out指定の仮引数は初期化されていないことから、代入の右辺には記述できない
・よって、p.193 swap03.csの「ref」を「out」にするとエラーになる
・また、古いバージョンのC#では利用できない

p.194 outkeyword01.cs

//p.194 outkeyword01.cs
using System;
class MyClass{
    public void Square(double x, double y, out double s) { //仮引数sは参照渡し
        s = x * y; //よってsをreturnする必要はない
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c;
        MyClass mc = new MyClass();
        //cには値を代入していません
        mc.Square(a, b, out c); //初期化していないcを参照渡しできる
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方メートル", a, b, c);
    }
}

補足:p.194 outkeyword01.csについて

・Squareメソッドは1値を返すようになっているので、outは必須ではない。下記で可能。
    public double Square(double x, double y) { 
        return x * y; 
    }

アレンジ演習:p.194 outkeyword01.cs

・引数xとyの和と積を返すメソッド public void AddMul(double x, double y, out double add, out double mul) にしよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass{
    public void AddMul(double x, double y, out double add, out double mul) { //仮引数add,mulは参照渡し
        add = x + y; //よってreturnする必要はない
        mul = x * y; //よってreturnする必要はない
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c, d;
        MyClass mc = new MyClass();
        mc.AddMul(a, b, out c, out d); //初期化していないc、dを参照渡しできる
        Console.WriteLine("和は{0}, 積は{1}", c, d);
    }
}