🐚

[魚戸ホタル] C#勉強備忘録4日目

2022/03/26に公開

おはようございます
こんにちは
ほたー

今回の備忘録は主なテーマは以下の3点です。

使用教材は亀田健司(著)1週間でC#の基礎が学べる本になります。

対象ページは以下の通りです。
1:162ページから186ページ
2:187ページから204ページ
3:205ページから228ページ

C#備忘録アーカイブ

C#におけるクラスとオブジェクト化

オブジェクト指向とはあらゆるものをすべて モノ として表現するという考え方のことをいいます。
オブジェクト指向のオブジェクトとは英語で「モノ」を表す言葉です。
例えば自転車をモノと考え、運転するには仕組みを考えずともペダルを漕ぐ、ハンドルを切る、ブレーキを踏むなどといった操作をすれば動くということです。
オブジェクトには操作にあたる メソッド とデータにあたる フィールドがあります。
自転車の例でいえば「ペダルを漕ぐ」「ブレーキを踏む」などがメソッドで、「スピード」「走行距離」がフィールドになります。

C#でオブジェクト指向を利用するためにはクラスという概念も必要になります。
例えばタイヤですとタイヤの設計図をもとに大量のタイヤが生産されています。
この設計図にあたるものがクラスです。
設計図であるクラスをもとに生産された実体がオブジェクトであり、英語で「実例」を意味するインスタンスとも呼びます。

オブジェクト指向を活用するとソフトウェア開発が効率的になります。
例えば人体のうち目、腕、指をそれぞれ「目クラス」、「腕クラス」、「指クラス」というように分けると、目クラスで掴みたいものに照準を合わせる、腕クラスで物に腕を伸ばす、指クラスで物を掴むといった具合に役割分担ができるので動作が理解しやすくなります。

それではオブジェクト指向について次のソースコードを書きました。
電子レンジで何W(ワット)で何秒温めるか入力した後に加熱情報を表示するプログラムです。
Microwave.csファイルを新規作成して、電子レンジのクラスMicrowaveを作成します。
C#では慣例的にクラス名とファイル名を同じにします。

メソッドの戻り値に void とありますが、意味としてはメソッドを実行しても何も返さないということです。
メソッドを実行すると返す値を 戻り値 といいます。
配列の形の入力データからデータの追加・除去処理を行ったあとに配列を返すメソッドや保存や更新等の処理結果をtrueもしくはfalseのboolean型で返すメソッドは業務でよく使っています。

(1)クラス名 Microwave

(2)フィールド

名前 内容
int wat 電子レンジのワット数
int seconds 電子レンジの加熱時間

(3)メソッド

戻り値の型 名前 引数 内容
void ShowHeatInformation なし 電子レンジの加熱情報の表示
void SetHeatInformation wat,seconds 電子レンジの加熱情報の登録
Microwave.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Microwave
    {
        // 電子レンジのワット数
        public int wat;
        // 電子レンジの加熱時間
        public int seconds;
        // 加熱情報の登録
        public void SetHeatInformation(int wat, int seconds)
        {
            this.wat = wat;
            this.seconds = seconds;
        }
        // 加熱情報の表示
        public void ShowHeatInformation()
        {
            Console.WriteLine("{0}Wで{1}秒加熱します。", wat, seconds);
        }
    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("電子レンジで加熱します。");
	    // Microwaveクラスのメソッドのインスタンスを生成
            Microwave m = new Microwave(); 
	    // 加熱情報の入力
            Console.Write("何Wで温めますか?:");
            int wat = int.Parse(Console.ReadLine());
            Console.Write("何秒温めますか?:");
            int seconds = int.Parse(Console.ReadLine());
            m.SetHeatInformation(wat, seconds);
	    // 加熱情報の表示
            m.ShowHeatInformation();
            Console.WriteLine(); 改行
        }
    }
}

実行結果

上記のソースコードを実行した結果、電子レンジの加熱情報を表示することができました。
プログラムが開始されるProgram.csからMicrowaveクラス内で作成したSetHeatInformationメソッドを呼び出して入力した加熱情報を登録し、最後にShowHeatInformationメソッドを呼び出して加熱情報を表示します。
SetHeatInformationを呼び出す際に入力したwat、secondsをカッコ内に入れていますが、これらは引数と呼ばれます。
引数はメソッドに外部から与えられる変数のことを言います。

加熱情報こそ表示できましたがMicrowaveクラスはまだまだ十分とは言えません。
理由としては加熱情報を書き換えられる可能性があるためです。
そのためカプセル化、インスタンスの生成と消去の説明においてそれぞれの方法でMicrowaveクラスの改良を行います。

C#におけるカプセル化

日々の生活でパソコンやスマートフォンの複雑な仕組みを意識しなくても、問題なく操作できています。
複雑な仕組みを隠し、必要最小限の操作で外部から操作することが推奨されており、この考え型を カプセル化 と言います。
カプセル化のためにフィールドやメソッドを保護する仕組みとして アクセス修飾子 があります。

オブジェクト指向言語では、アクセスが必要なフィールドにはそのフィールドにアクセスする丹野専用のメソッドを追加することで外部からの操作を行えないようにしています。
フィールドの値を取得するメソッドのことをオブジェクト指向プログラミングの世界ではセッター(setter)と言います。
その逆にフィールドの値を取得するためのメソッドのことをゲッター(getter)と言います。

それではこのセッターとゲッターを使ってMicrowaveクラスをリファクタリングします。
リファクタリングとはプログラムの実行結果を変えずに内部構造を整理することです。
整理方法としては例えば無駄なコードの除去や処理の分割があります。
リファクタリング後のMicrowaveクラスおよびProgram.csを次のように書きました。

Microwave.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Microwave
    {
        // 電子レンジのワット数
        private int wat;
        // 電子レンジの加熱時間
        private int seconds;
        // 加熱情報の表示
        public void ShowHeatInformation()
        {
            Console.WriteLine("{0}Wで{1}秒加熱します。", wat, seconds);
        }
        // ワット数のプロパティ
        public int Wat
        {
            set { wat = value; }
            get { return wat; }
        }
        // 加熱時間のプロパティ
        public int Seconds
        {
            set { seconds = value; }
            get { return seconds; }
        }

    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("電子レンジで加熱します。");
            // Microwaveクラスのメソッドのインスタンスを生成
            Microwave m = new Microwave();
            // 加熱情報の入力
            Console.Write("何Wで温めますか?:");
            m.Wat = int.Parse(Console.ReadLine());
            Console.Write("何秒温めますか?:");
            m.Seconds = int.Parse(Console.ReadLine());
            // 加熱情報の表示
            m.ShowHeatInformation();
            Console.WriteLine(); // 改行
        }
    }
}

実行結果

上記のソースコードを実行した結果は前回と同様です。
ただしMicrowaveクラスでwatフィールド、secondsフィールドを定義したときにpublicではなくprivateが前に付いています。
メソッドの前に付いた修飾子を アクセス修飾子 と呼び、フィールドおよびメソッドへのアクセスの制限を指定するために使用します。
C#のアクセス修飾子には書き写しではありますが以下のようなものがあります。

  • C#のアクセス修飾子[1]
名前 呼び名 意味
public パブリック どこからでもアクセスできる
protected プロテクティッド 同一クラスかそのサブクラスしかアクセスできない
internal インターナル 同一のアセンブリ(DLL)内でアクセスできる。
protected internal プロテクティッドインターナル protectedかつinternal
private プライベート 同じクラス内からしかアクセスできない

ShowHeatInformationメソッドはpublicなので外部のクラスであるProgramからアクセス可能ですが、フィールドにはprivateが付いているためクラスの外からアクセスできません。

Microwaveクラスのコメントでプロパティとありますが、これはセッターやゲッターを記述するための仕組みです。
セッター、ゲッターの記述は以下のようになります。
set{}、get{}の部分をアクセサーといい、そこにフィールドにアクセスする処理を書きます。

加熱情報を表示するソースコードに戻ります。
Program.csで以下のように書いてフィールドwatに数値を代入しています。
プロパティ名はフィールド名の先頭を大文字にします。
プロパティでフィールドに値を代入したことでSetHeatInformationメソッドは不要になったため除去しました。

最後に加熱情報を表示して終了します。

CakePHPではバージョン3.x以降でセッター、ゲッターの考えがあります。
今の職場ではCakePHP2から始めていたのでCakePHP3でモデルの機能がフィールドの値を操作するEntityとデータベースと接続するTableに分けられ一時は戸惑いました。
しかしオブジェクト指向の考えがより直感的になったとわかると便利になったと思いました。
詳しく知りたい方はこちら[2]を参照してください

またプロパティはセッターのみ、ゲッターのみの定義が可能です。
セッターのみでは書き込み専用になり、ゲッターのみでは読み込み専用になります。

セッター、ゲッターの考えからフィールドおよびメソッドへのアクセスを制限し、外部の操作から守る方法を学びました。
次はコンストラクタと呼ばれるクラス生成時に1回だけ呼び出されるメソッドについて学びます。

C#におけるインスタンスの生成と消去

C#のクラスにはインスタンス生成時に一度だけ呼び出される、コンストラクタ(constructor)という特殊なメソッドが存在します。
CakePHPではController、Modelで一度だけ呼び出されるメソッドとしてinitializeメソッドがございますので似たようなメソッドと考えました。

それではC#におけるクラスとオブジェクト化で書いたソースコードをコンストラクタを使う形でファクタリングします。
リファクタリング後のMicrowaveクラスおよびProgram.csを次のように書きました。

Microwave.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Microwave
    {
        // 電子レンジのワット数
        private int wat;
        // 電子レンジの加熱時間
        private int seconds;
        // コンストラクタ
        public Microwave(int wat, int seconds)
        {
            SetHeatInformation(wat, seconds);
        }
         // 加熱情報の登録
        private void SetHeatInformation(int wat, int seconds)
        {
            this.wat = wat;
            this.seconds = seconds;
        }
        // 加熱情報の表示
        public void ShowHeatInformation()
        {
            Console.WriteLine("{0}Wで{1}秒加熱します。", wat, seconds);
        }
        // デストラクタ
        ~ Microwave()
        {
            Console.WriteLine("チン");
        }

    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UotoHotaru0325_8
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("電子レンジで加熱します。");
            // 加熱情報の入力
            Console.Write("何Wで温めますか?:");
            int wat = int.Parse(Console.ReadLine());
            Console.Write("何秒温めますか?:");
            int seconds = int.Parse(Console.ReadLine());
            // Microwaveクラスのメソッドのインスタンスを生成
            Microwave m = new Microwave(wat, seconds);
            // 加熱情報の表示
            m.ShowHeatInformation();
            Console.WriteLine(); // 改行
        }
    }
}

実行結果

上記のソースコードを実行した結果は最後の「チン」以外は同じです。
コンストラクタは戻り値がなくクラス名と同じ名前のメソッドになります。
Microwaveクラスなのでメソッド名はMicrowaveです。
加熱情報を入力した後にMicrowaveクラスのメソッドのインスタンスを生成するときにコンストラクタが呼び出され、SetHeatInformationメソッドに引数のwat、secondsを渡し、加熱情報を登録します。
コンストラクタに引数を設定していますが、引数なしのコンストラクタを設定することも可能です。

加熱情報を表示した後に実行結果で「チン」という文字を表示していますが、これはデストラクタと呼ばれるメソッドが実行された結果です。
デストラクタはインストラクタが破棄されたときに呼び出されるメソッドで、今回はMain()メソッドが終了したときに呼び出されています。
デストラクタの書き方はクラス名の後ろに~(チルダ)を付け、アクセス修飾子は付けません。
理由は明示的に呼び出すように設定することができないためです。

インスタンスの生成と消去における他のポイントを箇条書きで書きます。
詳しい内容を知りたいのであれば使用教材を読むことを推奨します。

ポイント

  • メモリを使い切らないように不要なインスタンスを整理する仕組みをガーベージコレクション(garbage collection)という
  • C#の型には大きく分けて値型、参照型がある。
  • 値型変数が保存される変数の領域のことをスタック(Stack)という。
  • クラスのインスタンスのようにnew演算子を用いて生成するデータが存在するメモリのことをヒープ(Heap)という。

以上で4日目の備忘録は終了となります。

最後に

C#のオブジェクト指向の問題を書いてみて、仕事中に手で動かした感覚から考え方が呑み込めていますが、実際に備忘録に残す形で見やすく説明する文章を書くとなると時間がかかるなあと思います。

オブジェクト指向の考え方はC#を理解するためには必須、パーソナリティですから、そういうものと受け止めます。

ありがとうございました。Thank You。

脚注
  1. 1週間でC#の基礎が学べる本 191ページ ↩︎

  2. CakePHP4 アクセサーとミューテーター ↩︎

Discussion