講義メモ

・文法編:ジェネリクス、ToStringメソッド など
・ゲーム開発編:特別編「3D迷路&シューティングゲーム開発演習」

文法編:ジェネリクス

・p.187の説明の通り、下記の構文の「<型名>」の構文をジェネリクスという
 Vegetable.Type typeA = GetComponent<Vegetable>().type;
・C言語などでは、同じ処理内容でも、用いるデータの型が異なる場合、その違いの数だけ名前の異なる関数を作成する必要がある
・これを改良する考え方がオーバーロードで、用いるデータの型が異なれば同じ名前の関数(メソッド)にできる
・さらに、改良して、用いるデータの型をパラメータとして与えられるようにしたのが、ジェネリクス(ジェネリックメソッド)
・GetComponentはUnityが提供するジェネリックメソッドであり、プログラマが自前で定義することも可能
・用いるデータの型を受け渡すパラメータを型パラメータといい、大文字のTなどを用いることが多い

文法編:ジェネリックメソッドの例:同じ型の2引数を受け取って両方を出力するメソッド

・int型用は public void Log2(int a, int b) { Debug.Log(a);  Debug.Log(b); }
・double型用は public void Log2(double a, double b) { Debug.Log(a);  Debug.Log(b); }
・これをジェネリックメソッドにすると、型パラメータを引数型にも用いて下記のようにできる
 public void Log2<T>(T a, T b) { Debug.Log(a);  Debug.Log(b); }
・そして、呼び出しにおいて、型情報を渡すと、それに応じたメソッドが自動生成&利用される
 Log2<int>(10, 20);
 Log2<double>(3.14, 2.22);

演習 ex0914a.cs

・上記の例を試すプログラムを作成しよう

作成例

//演習 ex0914a.cs
using UnityEngine;
public class ex0914a : MonoBehaviour{
    public void Log2<T>(T a, T b) { //ジェネリックメソッド(引数型がT)
        Debug.Log(a);  Debug.Log(b); 
    }
    void Start()    {
        Log2<int>(10, 20); //型としてintを指定してジェネリックメソッドを呼ぶ
        Log2<double>(3.14, 2.22); //型としてdoubleを指定してジェネリックメソッドを呼ぶ    
    }
}

文法編:ジェネリッククラス

・クラス定義そのものをジェネリックにして、クラス内で型パラメータを使いまわすことも可能
・これをジェネリッククラスという
・例:
    class Nums<T> { 
        public void Log2(T a, T b) { //ジェネリックメソッド(引数型がT)
            Debug.Log(a);  Debug.Log(b); 
        }
    }
・ジェネリッククラスはオブジェクトの生成時に型パラメータを渡すことができる
・例:
    Nums<int> num = new Nums<int>();

演習 ex0914b.cs

・上記の例を試すプログラムを作成しよう

作成例

//演習 ex0914b.cs
using UnityEngine;
public class ex0914b : MonoBehaviour{
    class Nums<T> { //ジェネリッククラス
        public void Log2(T a, T b) { //メソッド(引数型がTで得られる)
            Debug.Log(a);  Debug.Log(b); 
        }
    }
    void Start()    {
        Nums<int> num = new Nums<int>(); //ジェネリッククラスに型を与えてオブジェクト生成
        num.Log2(10, 20); //メソッドの引数型が決まる
        Nums<char> cnum = new Nums<char>();
        cnum.Log2('A', 'x');
    }
}

文法編:C#が提供するジェネリックコレクションクラス

・コレクションクラスとはデータ構造を提供する汎用クラス
・例えば、配列の機能を拡張するクラスである ArrayListクラスがあり、配列の弱点である
「要素数が固定」「格納するデータの型が固定」「途中挿入や途中削除ができない(手間がかかる)」
 などを解消している
 参照: https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.arraylist
・しかし、要素の型情報がない
(格納と同時にObject型に変換されてしまう=型情報が失われるので、プログラム側で管理する必要がある)ため、
 現在では、代わりに ジェネリックコレクションクラスList<T>を用いることが推奨されている
・利用方法
 冒頭に「using System.Collections.Generic;」を挿入(Unityでは自動挿入されることもある)
 生成: List<型> オブジェクト名 = new List<型>();
 格納: オブジェクト名.Add(要素値)メソッドで
 要素数: オブジェクト名.Count プロパティで
 要素値: オブジェクト名[添字] で配列と同様に
 参照: https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic.list-1

演習 ex0914c.cs

・Monsterクラスを定義し、中にpublicで文字列型のデータメンバnameを置く
・ジェネリックコレクションクラスList<Monster>のオブジェクトmonsを生成
・適当なMonsterオブジェクトをいくつか生成しつつ、monsに格納する
・要素数を表示
・全要素のnameを表示

作成例

using System.Collections.Generic;
using UnityEngine;
public class ex0914c : MonoBehaviour{
    class Monster {
        public string name;
        public Monster(string name) { //コンストラクタ
            this.name = name;
        } 
    }
    void Start()    {
        List<Monster> mons = new List<Monster>(); //ジェネリックコレクションを生成
        mons.Add(new Monster("ヴェルドラ")); //Monsterを生成して格納
        mons.Add(new Monster("リムル"));
        mons.Add(new Monster("シュナ"));
        Debug.Log("要素数:" + mons.Count); //プロパティで格納済要素数を得る
        foreach (var m in mons) { //全要素について繰返す
            Debug.Log("名前:" + m.name); //各要素のデータメンバを得て出力
        }
    }
}

文法編:ToStringメソッド

・C#のクラス構造の原則として「全クラスは自動的にObjectクラスの派生クラス扱い」
・よって、Objectクラスのメンバが自動的に継承されている
・その一つがToStringメソッドで、内容はクラスを表す文字列になる
 例: "ex0914c+Monster"
・C#では、自前のクラスの定義時に、ToStringメソッドをオーバーライドして、オブジェクトを表す文字列をreturnすることを推奨している
・なお、オブジェクトを文字列に連結したり、対応するメソッドに渡すと、自動的にToStringメソッドが呼び出される

演習 ex0914c.cs

・上記を試してみよう

作成例

using System.Collections.Generic;
using UnityEngine;
public class ex0914c : MonoBehaviour{
    class Monster {
        public string name;
        public Monster(string name) { //コンストラクタ
            this.name = name;
        }
        public override string ToString() { //自動継承したメソッドのオーバーライド
            return "My name is " + this.name; //自オブジェクトを表す文字列を返す
        }
    }
    void Start()    {
        List<Monster> mons = new List<Monster>(); //ジェネリックコレクションを生成
        mons.Add(new Monster("ヴェルドラ")); //Monsterを生成して格納
        mons.Add(new Monster("リムル"));
        mons.Add(new Monster("シュナ"));
        Debug.Log("要素数:" + mons.Count); //プロパティで格納済要素数を得る
        foreach (var m in mons) { //全要素について繰返す
            Debug.Log("名前:" + m); //各要素のToString()メソッドを自動的に呼ぶ
        }
    }
}

コメントを残す

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