前回のコメント

・静的メンバとインスタンスメンバが混在するケースは多いのでしょうか?

 クラスの設計によりますが、ごく普通です。
 敢えて、静的クラスにしている場合を除き、基本的にはインスタンスメンバで構成しますが、
 必要であれば、静的メンバを加えるというパターンが多いように思います。
 なお、混在を認めないチームルールにしている場合もあるようです。

・以下のエラーを確認しました。
 Name = “マイケル”;
 静的でないフィールド、メソッド、またはプロパティ‘CatName’で、オブジェクト参照が必要です
 ShowCat();
 静的でないフィールド、メソッド、またはプロパティー‘Cat.ShowCat()’で、オブジェクト参照が必要です
 this.Name = “”;
 キーワード‘this’は、静的プロパティ、静的メソッド、または静的フィールド初期化子では無効です

 何よりです。
 
・すみません、ファイルの添付を忘れました。

 提出は何回でもOKです。

講義メモ 後半

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

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

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

・forは前判定繰返しなので、animal.lengthが0の場合、繰返し内容は1度も実行されない。よって、if文は不要なことを確認しよう
・for文をforeach文にしよう
・引数に数値を含むとエラーになることを確認しよう

作成例

//アレンジ演習:p.201 params01.cs
using System;
class MyClass {
    public void show(params string[] animal) { //可変個引数
        //if (animal.Length == 0) //【削除】
        //    return; //【削除】
        foreach (var w in animal) {
            Console.WriteLine("{0}さんがいます", w);
        }
    }
    public void show(string animal) { //
        foreach (var w in animal) {
            Console.WriteLine("{0}さがいます", w);
        }
    }
}
class params01 {
    public static void Main() {
        int[] x = {0,1,2};
        MyClass mc = new MyClass();
        mc.show();
        mc.show("きりん", "ぞう", "かば");
        //mc.show("きりん", "ぞう", "かば", 1); //文字列に暗黙変換ができない引数があるとエラー
    }
}

補足:可変個引数と通常の引数の共存

・可変個引数と通常の引数は共存できる。ただし、可変個引数を末尾にすること
・よって、可変個引数は1つしか指定できない
 例:public void show(int i, params string[] animal) {…}
 こうすると、mc.show(0)、mc.show(0, "hoo")、mc.show(0, "hoo", "voo"); などの呼び出しが可能。
 ただし、mc.show()、mc.show("hoo")などの呼び出しはエラーになる。

補足:可変個引数とオーバーロード

・呼び出しにおいて区別できる限り、可変個引数を用いたメソッドのオーバーロードは可能
・ただし、引数の与え方により、呼び出しが区別できない場合は、呼び出し側がエラーになる
 例:void all(params int[] a) {…}、void all(params string[] a) {…} の場合:
 こうすると、all(0)、all(0, 1)、all("hoo", "voo"); などの呼び出しが可能。
 ただし、all()、mc.show(0, "hoo")などの呼び出しはエラーになる。
・また、可変個引数を用いたメソッドと可変個引数を用いないメソッドのオーバーロードも可能
・ただし、引数の与え方により、呼び出しが区別できない場合は、用いないメソッドが優先される

ミニ演習:mini0810a.cs

・可変個引数を用いたメソッドと可変個引数を用いないメソッドのオーバーロードで、引数の与え方により、呼び出しが区別できない場合は、
 用いないメソッドが優先されることを試そう

作成例

//ミニ演習:mini0810a.cs
using System;
class MyClass {
    public void show(params string[] animal) { //可変個引数なメソッド①
        foreach (var w in animal) {
            Console.WriteLine("{0}さんがいます", w);
        }
    }
    public void show(string animal) { //可変個引数ではないメソッド②
        Console.WriteLine("{0}がいます", animal);
    }
}
class params01 {
    public static void Main() {
        int[] x = {0,1,2};
        MyClass mc = new MyClass();
        mc.show("ひと"); //①②の両方が当てはまるが②が実行される
        mc.show("きりん", "ぞう", "かば"); //①が実行される
    }
}

p.202 静的メンバ

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

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

・デフォルトコンストラクタを追加し、その中で静的メンバ変数xをインクリメントしよう
・Mainメソッドで静的メンバ変数xの最初の値を10ではなく0にしよう
・そして、MyClassのインスタンスを生成してから、ShowX()メソッドを実行することを繰返してみよう

作成例

// 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() { //実はMainも静的メソッド
        MyClass.x = 0; //【変更】静的データメンバなので「クラス名.」で利用可能
        MyClass.showX(); //静的メソッド「クラス名.」で実行可能
        new MyClass(); //【以下追加】デフォルトコンストラクタを呼ぶ
        MyClass.showX(); //1になっている
        new MyClass(); //デフォルトコンストラクタを呼ぶ
        MyClass.showX(); //2になっている
    }
}

p.204 静的クラス

・静的メンバのみによるクラスは、静的クラスにすることができる
・書式: static class クラス名 {…}
・義務はないが、静的クラスにしておくことで、誤って静的ではないメンバが出現することを防止できる
 ※ 例えば、固定データのみを持つクラスや、数値関数のみを持つクラスなど(特殊な事例)

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

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

作成例

//アレンジ演習:p.204 static02.cs
using System;
static class MyClass { //静的クラス
    public static int x; //静的データメンバ
    // int y; //インスタンス変数を記述するとエラー
    public static void showX() { //静的メソッド
        System.Console.WriteLine("x = {0}", x);
    }
    // void foo() { } //インスタンスメソッドを記述するとエラー
}
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

・静的メソッドSetCatTail()の中の「// name = "マイケル";」をコメントアウトしないと、どういうエラーになるか確認しよう
・静的メソッドSetCatTail()の中で、インスタンスメソッドShowCat()を呼ぶとエラーになることを確認しよう
・静的メソッドSetCatTail()の中で、thisを用いるとエラーになることを確認しよう
・以上は、確認後、コメントアウトすること

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

講義メモ

・p.192「refとout:outキーワード」の補足後、p.195「メソッドのオーバーロード」に進みます

p.192 refとout:outキーワード

・refキーワードの上位版がoutキーワードで、refの「実引数はなんらかの値が代入されている必要がある」という制限がない
※C#のバージョン7以降では、outキーワードの仕様が強化され、outキーワードで指定する実引数は、
 事前の定義が不要になり「out 型 実引数名」とすれば良い。
 この実引数は呼出し以降にそのまま利用可能。

参考:配列を渡して最大値と最小値を返すメソッド

using System;
class MyClass
{
    public void ArrayMaxMin(double[] x, out double max, out double min) { //max,minは参照渡し
        max = Double.MinValue; min = Double.MaxValue; //仮に最小値・最大値にしておく
        foreach (var w in x) { //全要素について繰返す
            max = (max > w) ? max : w; //最大値を更新
            min = (min < w) ? min : w; //最小値を更新
        }
    }
}
class outkeyword01
{
    public static void Main()
    {
        double[] a = {125.3, 16.25, 52.8}; 
        MyClass mc = new MyClass();
        mc.ArrayMaxMin(a, out double maxv, out double minv);
        Console.WriteLine("max = {0}, min = {1}", maxv, minv);
    }
}

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

・変数cの定義を省き、実引数の指定を「out double c」とできることを確認しよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass
{
    public void Square(double x, double y, out double s) { //仮引数sは参照渡し
        s = x * y;
    }
}
class outkeyword01
{
    public static void Main()
    {
        //double a = 125.3, b = 16.25, c;
        double a = 125.3, b = 16.25; //変数cを削除
        MyClass mc = new MyClass();
        //cには値を代入していません ⇒ 宣言すらしていません
        mc.Square(a, b, out double c); //out指定の実引数は事前の宣言が不要
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方メートル", a, b, c);
    }
}

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)); //intなので①
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3.2)); //doubleなので②
        Console.WriteLine("その戻り値は「{0}」です", m.Method("粂井")); //stringなので③
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5, 6)); //int,intなので④
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5.1, 6)); //【追加】double,intだが⑤
    }
}

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

・変数nの宣言と代入を初期化にまとめよう
・forは前判定繰返しなので、nが0の場合、繰返し内容は1度も実行されない。よって、if文は不要なことを確認しよう

作成例

//アレンジ演習:p.198 main01.cs
using System;
class main01 {
    public static int Main(string[] s) { //コマンドライン引数を受け取り、整数値を返すMain
        int n = s.Length; //【変更】コマンドライン引数の数を得る
        Console.WriteLine("引数の個数は{0}個です", n);
        for (int i = 0; i < n; i++) { //全要素について繰返す
            Console.WriteLine("引数{0} : {1}", i + 1, s[i]);
        }
        return 0;
    }
}

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

① ソースを記述し「ビルド」「ソリューションのビルド」(※既に実行済なら不用)
②「ツール」「コマンドライン」「開発者用コマンドプロンプト」
③ エクスプローラで「プロジェクト名.exe」ファイルがあるフォルダを探す
 例:\ha251_AkibaC#\chap8\chap8\bin\Debug\chap8.exe
④「プロジェクト名.exe」ファイルをエクスプローラから開発者用コマンドプロンプトへドラッグ&ドロップ
⑤ パス名を含むファイル名がペーストされるので、空白を挟みつつ、コマンドライン引数を入力
 例:D:\ha251_AkibaC#\chap8>D:\ha251_AkibaC#\chap8\chap8\bin\Debug\chap8.exe boo hoo woo
⑥ Enterキーで実行
⑦ 実行後「echo %errorlevel%」と入力すると、returnされた値が表示される

アレンジ演習:p.198 main02.cs

・returnを実行すると後続の処理は行われないので、elseブロックが不要なことを確認しよう
・実行しても何も表示されないので、確認用に各returnの前で返した値を表示しよう
・わかりづらく実行環境に依存するバッチファイルを使わずに、開発者用コマンドプロンプトを用いて試そう

作成例

//アレンジ演習:p.198 main02.cs
using System;
class main02 {
    public static int Main(string[] args) { //コマンドライン引数を受け取り、整数値を返すMain
        if (args.Length != 1) {
            Console.WriteLine("return -1"); //【追加】
            return -1;
        }
        if (!Char.IsDigit(args[0][0])) { //【変更】
            Console.WriteLine("return -2"); //【追加】
            return -2;
        }
        Console.WriteLine("return {0}", int.Parse(args[0])); //【追加】
        return int.Parse(args[0]);
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位は「鬼滅の刃 ヒノカミ血風譚2(Switch)」 GO!
釣りゲーに料理シムに…他にもいろんな用途がありそう!Joy-Con 2クランク型はじめとする複数アタッチメントの特許申請情報が公開 GO!
AI推論と高速配信の両立でユーザーの「待てない」を解消―Akamaiが打ち出す、AI時代のゲームインフラの新機軸【CEDEC 2025レポート】GO!
オンラインゲームの遅延問題に終止符を。―Akamaiが提供する“世界で最も分散したネットワーク”とは?コスト90%削減を実現したDB連携事例も【CEDEC2025レポート】 GO!
「RTA in Japan Summer 2025」が本日8月9日15時より開催!高難度2DACT『Cuphead』から GO!
GPT-5はgpt-oss-120b、Claude Opus 4.1とどのくらい違う?―小説執筆とヴァイブ・コーディングで試してみた(CloseBox)GO!

ソニーに提訴された『LIGHT OF MOTIRAM』Steamストアページの画像を変更―『Horizon』シリーズとの類似性が目立つものが対象か GO!
すべてが文字のみで構成されたテキストADV『文字遊戯』Steam日本語版配信が無期延期に―すれ違うSteam運営との認識 GO!

前回のコメント

・以下のエラーメッセージを確認しました。
 int z;
 s.swap(ref x, ref z);
 未割り当てのローカル変数‘z’が使用された
 s.swap(ref x, ref (x + y));
 refまたはout値は、割り当て可能な変数でなければなりません
 s.swap(ref x, ref (200));
 refまたはout値は、割り当て可能な変数でなければなりません

 はい、この通りです。それぞれの意味を理解しておいてください。

・キーワードの参照により、呼び出し側の引数を入れ替えられたりするとのことですが、refキーワードやoutキーワードなどはどういった場面で使われるのでしょうか。

 ref/outキーワードを用いて引数を参照渡しにすることで、
 メソッド内で仮引数の値を操作すると、実引数の値に反映します。
 よって、本来は最大1つの情報しか返せないメソッドで複数の情報を返すことができます。
 また、メソッドへのデータ操作の依頼がわかりやすくなります。
 テキストではこのことを利用する一例として、値の入れ替え(swap)を行っていますが、
 配列などのデータ構造を渡して最大値と最小値を返すメソッドなどにも便利です。
 
 

講義メモ 第8章 クラスとメソッドの詳細

p.181 メソッドの再帰呼び出し

・C#などのメソッドは内部で自分自身を呼び出すことが可能で、これを再帰(リカージョン)という
・再帰を用いることで、アルゴリズムを単純化できることがある
・なお、再帰を用いる場合は「場合によっては自分自身を呼び出さず、値を返す」処理が必要で、
 これがないと無限ループする
 ※「再帰の終了条件」ともいう

p.181 階乗を計算する

・階乗とはある正の整数において、その数から1までの全整数の積のことで「整数!」と表す
・例: 3! = 3×2×1 = 6、4! = 4×3×2×1 = 24
・階乗は繰返し構文で計算可能だが、n! = n × (n - 1)! であることを用いて再帰でシンプルに記述できる
・例: 3! = 3×2×1 = 6、4! = 4×(3×2×1) = 4×3!
・なお、0の階乗及び1の階乗は1と定められているので、p.182 fact01.csでは0の階乗が1であることを
 再帰の終了条件にしている

アレンジ演習:p.182 fact01.cs

・0の階乗が1であることを再帰の終了条件にしているが、1の階乗も1であることを加味して効率化しよう
・条件演算子を用いてCalcFactメソッドを簡略化しよう

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact {
    public long CalcFact(int n) { //n!を返す再帰を含むメソッド
        return (n == 0 || n == 1) ? 1 : n * CalcFact(n - 1); //0!=1!=1、n!=n*(n-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とし、3要素目以降は前2要素の和を値とする数列
・例: 1, 1, 2, 3, 5, 8, 13, 21, 34,…
・各種のシミュレーション、統計処理に利用されている
・これは、先頭を1要素目とすると、3要素目は1要素目+2要素目なので、n要素目は
 「(n-2)要素目+(n-1)要素目」
 という再帰表現にできる
・なお、再帰の終了条件は「1要素目と2要素目は1」を用いると良い

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

・条件演算子を用いてメソッドを簡略化しよう

作成例

//アレンジ演習:p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) { //フィボナッチ数列のn番目の値を返す(先頭を1番目とする)
        return (n == 1 || n == 2) ? 1 : CalcFibo(n - 1) + CalcFibo(n - 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:前提の説明「値渡しについて」

・メソッドの仮引数には、実引数で指定された値や式の評価の値が渡される
・このことを値渡しという
・p.189 swap01.csは、Swapメソッドの中で仮引数の値を書き換えており、実引数の値が書き換わると考えたプログラム
・実引数と仮引数が同じ名前なので誤解を招きやすいが、コピーされた値が用いられるので、実引数の値は変化しない

p.190 refとout:前提の説明「参照型における値渡しについて」

・他の言語では参照型の引数を用いると、値渡しにならず、実引数に参照型変数を指定し、
 仮引数を操作すると実引数が書き換わるものもあるが、C#では値渡しになる
・よって、p.190 swap02.csは、p.189 swap01.csと同様になり、実引数の値は変化しない

p.191 refとout:前提の説明「配列を実引数にすると参照渡しになる」

・p.191 changearrray01.csの通り、配列を実引数にすると配列の位置情報(参照)が値として渡されるので、
 仮引数も同じ配列を指すことになる
・よって、配列を実引数にすると値渡しでなく、参照渡しと呼ばれる受け渡しになる
・よって、仮引数である配列の要素値を操作すると、実引数である配列の要素値が変化する
・もちろん、仮引数である配列と実引数である配列の配列名は同じである必要はない

アレンジ演習:p.191 changearrray01.cs

・「new int[3]」を省略して、配列の末尾に要素「4」を追加しよう
・すると、プログラムの他の部分をまったく変更しなくてよいことを確認しよう

作成例

//アレンジ演習:p.191 changearrray01.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 = {1, 2, 3, 4}; //【変更】
        Console.WriteLine("----modifyメソッド実行前----");
        int i = 0;
        foreach (int x in myarray) { //全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x); 
            i++;
        }
        c.modify(myarray); //配列をメソッドに渡して書き換えてもらう
        Console.WriteLine("----modifyメソッド実行後----");
        i = 0;
        foreach (int x in myarray) { //全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++;
        }
    }
}

テキスト正誤 p.191 changearrray01.cs 1行目

【誤】// charngearrray01.cs
【正】// changearrray01.cs

ミニ演習:p.191 changearrray01.cs ⇒ changearrraylist.cs

・changearrray01.csの配列をArrayListオブジェクトに変更して、動作を確認しよう

作成例

//ミニ演習:p.191 changearrray01.cs ⇒ changearrraylist.cs
using System;
using System.Collections; //【追加】
class change {
    public void modify(ArrayList array) { //【変更】アレイリストを受け取るメソッド(参照渡しになる)
        int n = array.Count; //【変更】受け取ったアレイリストの要素数を得る
        for (int i = 0; i < n; i++) { //全要素について繰返す
            int w = (int)array[i] * 2; //【変更】要素値を取り出して2倍にする
            array[i] = w; //【追加】再格納する
        }
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        ArrayList myarray = new ArrayList(); //【追加】アレイリストのオブジェクトを生成
        for (int n = 1; n <= 4; n++) { //【以下追加】
            myarray.Add(n); //アレイリストに格納
        }
        Console.WriteLine("----modifyメソッド実行前----");
        int i = 0;
        foreach (int x in myarray) { //全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x); 
            i++;
        }
        c.modify(myarray); //アレイリストをメソッドに渡して書き換えてもらう
        i = 0;
        foreach (int x in myarray) { //全要素について繰返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++;
        }
    }
}

p.192 refとout:refキーワード

・ここまでの説明の通り(配列のような構造を渡す場合を除いて)引数においては値渡しが基本であり、
 メソッド側で仮引数の値を操作しても、実引数には反映しない。
・これを参照渡しに切り替えるのがrefキーワード
・実引数と仮引数の双方にrefキーワードを与えると、メソッド側で仮引数の値を操作すると実引数には反映する。
・実引数名と仮引数名が異なっても構わない。
・なお、refキーワードを付けて用いる実引数はなんらかの値が代入されている必要がある
・また、呼び出し側で式やリテラルを実引数として与えると文法エラーになる

アレンジ演習:p.193 swap03.cs

・「refキーワードを付けて用いる実引数はなんらかの値が代入されている必要がある」ことを試そう
・「呼び出し側で式やリテラルを実引数として与えると文法エラーになる」ことを試そう
・どちらも、確認したらコメントアウトすること

作成例

//アレンジ演習: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); //実引数xとyは参照渡しになる(値が書き換わる)
        Console.WriteLine("x = {0}, y = {1}", x, y); //値が交換されている
        //int z;
        //s.swap(ref x, ref z); //「未割当のローカル変数zが使用された」という文法エラーになる
        //s.swap(ref x, ref(x + y)); //「割当て可能な変数でなければならない」という文法エラーになる
        //s.swap(ref x, ref(200)); //「割当て可能な変数でなければならない」という文法エラーになる
    }
}

p.192 refとout:outキーワード

・refキーワードの上位版がoutキーワードで、refの「実引数はなんらかの値が代入されている必要がある」という制限がない
※C#のバージョン7以降では、outキーワードの仕様が強化され、outキーワードで指定する実引数は、
 事前の定義が不要になり「out 型 実引数名」とすれば良い。
 この実引数は呼出し以降にそのまま利用可能。

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

・変数cの定義を省き、実引数の指定を「out double c」とできることを確認しよう

提出:アレンジ演習:p.193 swap03.cs、または、アレンジ演習:p.194 outkeyword01.cs

講義メモ

・p.176「既存のクラスを使ってみる」から

補足:thisの用途(コンストラクタからコンストラクタを呼ぶ)

・コンストラクタに「: this(引数,…)」を記述することで、他のコンストラクタに引数を渡して呼び出すことができる
・例えば、public クラス名(int a, int b) {…} があれば、
 public クラス名(int a) : this(a, 100) {} とすることで、上のコンストラクタを呼び出せる
 public クラス名() : this(200) {} とすることで、上のコンストラクタを呼び出せる
・この場合、コンストラクタの本文は空出も構わないが「{}」は省略不可
・なお、近い構文に「: base(引数,…)」があり、継承時のコンストラクタの扱いに用いる(p.245)

利用例:アレンジ演習:p.169 construct02.cs:コンストラクタからコンストラクタを呼ぶ

//アレンジ演習:p.169 construct02.cs:コンストラクタからコンストラクタを呼ぶ
using System;
class MyClass {
    private string name; //氏名(外部からの直接利用不可) 
    private int age; //年齢(外部からの直接利用不可)
    private string address; //住所(外部からの直接利用不可)
    public void Show() { //表示用のメソッド
        string toshi; //年齢情報の表示用の変数(このメソッド内でのみ有効な作業変数)
        if (age == -1) {
            toshi = "不明";
        } else {
            toshi = age.ToString(); //整数から文字列に変換して代入
        }
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi);
    }
    public MyClass(string str1, string str2, int x) { //コンストラクタ③(string,string,int) 全て
        name = str1;  //氏名は引数1から
        address = str2;  //住所は引数2から
        age = x;  //年齢は引数3から
    }
    public MyClass(string str) : this(str, -1) { }//コンストラクタ①(string) 氏名のみ⇒④を呼ぶ
    public MyClass(int x) : this("不明", "不定", x) { } //コンストラクタ②(int) 年齢のみ⇒③を呼ぶ
    public MyClass(string str, int x) : this(str, "不定", x) { } //コンストラクタ④(string,int) 氏名と年齢⇒③を呼ぶ
    public MyClass() : this(-1) { } //デフォルトコンストラクタ⇒②を呼ぶ
}
class construct01 {
    public static void Main() {
        MyClass mc1 = new MyClass(18); //コンストラクタ②(int) 年齢のみ を呼ぶ
        MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①(string) 氏名のみ を呼ぶ
        MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③(全部)を呼ぶ
        mc1.Show();
        mc2.Show();
        mc3.Show();
        MyClass mc4 = new MyClass("シャア", 20); //【追加】コンストラクタ④(string,int)を呼ぶ
        mc4.Show(); //【追加】
        MyClass mc5 = new MyClass(); //【追加】デフォルトコンストラクタ()を呼ぶ
        mc5.Show(); //【追加】
    }
}

p.176 既存のクラスを使ってみる

・すでに用いている「Console.Write(…)」メソッドなどの「Console」や、「Math.Sin(…)」メソッドなどの「Math」などは
 C#が提供するクラス
・C#が提供するクラスの中には効率的なデータ構造を提供するコレクションクラスが含まれている
・代表的なコレクションクラスがArrayListクラスで、自由度の高い配列機能を提供する
・ArrayListオブジェクトでは、要素数の変更や、その時点の要素数を得る手段などを利用できる
 ※テキスト中にある「プロパティ」についは8章で後述するが、引数のない簡易的なメソッド。
・ArrayListオブジェクトに格納した要素は、配列要素と同様に添字で直接扱うことも可能
・利用には「using System.Collections;」を用いると良い
・Countプロパティ(要素数を得る手段)とfor文を用いることで、全要素に対する処理を記述できるが、
 閲覧用であればforeachを用いることも可能

アレンジ演習:p.177 ArrayList01.cs

・forの代わりにforeachを用いよう
・終了フラグbEndを用いないようにしよう

作成例

//アレンジ演習:p.177 ArrayList01.cs
using System;
using System.Collections;
class arraylist01 {
    public static void Main() {
        //bool bEnd = false; //【削除】終了フラグをオフにしておく
        string strData; //入力用
        double sum = 0.0; //合計
        ArrayList al = new ArrayList(); //配列機能を持つアレイリストクラスのオブジェクトを生成
        while (true) { //無限ループ
            Console.Write("データ(数値以外入力で終了)-- ");
            strData = Console.ReadLine();
            if (!Char.IsDigit(strData[0]) && strData[0] != '-') { //先頭文字が数字ではなく'-'でもない
                //bEnd = true; //【削除】終了フラグをオン
                break; //【移動】
            } else {
                al.Add(double.Parse(strData)); //入力文字列を実数変換してアレイリストに格納
            }
        }
        int n = 0; //【追加】添字の代わり
        foreach (var w in al) { //【変更】全要素について繰り返す
            Console.WriteLine("Data[{0}] = {1}", n++, w);
            sum += (double)w; //実数に逆変換して合計に足し込む
        }
        int count = al.Count; //Countで要素数を得る
        double avr = sum / count; //合計を要素数で割って平均を得る
        Console.WriteLine("データ個数 = {0}", count);
        Console.WriteLine("平均値 = {0}", avr);
    }
}

p.180 練習問題1 ex0701.cs 指針とヒント

・変数名、クラス名などは自由
・Mainメソッドはこのクラスとは別のクラスに配置すると良い
・よって、インスタンスの生成が必要

作成例

//p.180 練習問題1
using System;
class MyClass {
    public int age;
}
class arraylist01 {
    public static void Main() {
        MyClass m = new MyClass(); //オブジェクトを生成
        m.age = 63;
        Console.WriteLine("m.age = {0}", m.age);
    }
}

p.180 練習問題2 ヒント

・メソッド名、クラス名などは自由
・テキスト中ではコンストラクタのオーバーロードしか説明していないが、講義メモの通り、メソッドもオーバーロードが可能
・int型2値の和を求めるメソッドの戻り値型はint、double型2値の和を求めるメソッドの戻り値型はdoubleとすれば良い

作成例

//p.180 練習問題2
using System;
class MyClass {
    public int Add(int a, int b) { //整数和を返すメソッド①
        return a + b;
    }
    public double Add(double a, double b) { //実数和を返すメソッド②
        return a + b;
    }
}
class ex0702 {
    public static void Main() {
        MyClass m = new MyClass(); //オブジェクトを生成
        Console.WriteLine("m.Add(1, 2) = {0}", m.Add(1, 2)); //(int,int)なので①を呼ぶ
        Console.WriteLine("m.Add(1.1, 2.2) = {0}", m.Add(1.1, 2.2)); //(double,double)なので②を呼ぶ
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位も「マリオカート ワールド(Switch2)」 GO!
サイバーステップはオンクレ『トレバ』不振で5期連続の赤字、暗号資産事業で活路を模索【ゲーム企業の決算を読む】 GO!
「スイッチ2」全世界売上600万台突破。『マリカ ワールド』も563万本、初代スイッチを大きく上回る GO!
【キャリアクエスト】ツールが便利になる今、プログラマーに必要とされるものとは?アトラスで働くなかで見えてきた「プログラマーならではの仕事」GO!
「東京ゲームショウ2025」ビジネスデイ有料事前登録が開始!SIE社長・西野秀明氏による基調講演も決定 GO!
音楽はAIとの音声対話で作る時代に入った。Riffusion改めProducer.aiのAIプロデューサーと日本語で会話するだけで曲を作ってくれるのだ GO!
インディーゲームの祭典「BitSummit the 13th」なんと5万8,000人以上が来場。来年は開催時期5月に、猛暑は回避? GO!

成人向けゲームの規制に揺れるitch.io、寄付すら不可の「無料の成人向けゲーム」に限り表示再開を実施―決済代行業者を経由しないため GO!
「プラチナゲームズ」を名乗る不審なメールに注意喚起―求人募集を装って送付、フィッシング詐欺等の可能性も GO!