テキスト編:p.367(ジェネリックとコレクションクラス)から
ゲーム開発演習:ハイスコア処理、敵機出現のランダム化、他
p.367(ジェネリックとコレクションクラス)
・ArrayListクラス(p.177)のように、データ構造を提供するクラスがコレクションクラス。 ・コレクションクラスの中には、ジェネリッククラスもあり、その代表的な存在がC ・List<T>クラスは、格納したいオブジェクトの型を型パラメータで指定して用いる。 ・すると、配列と同様に利用できて、かつ配列より柔軟なデータ構造となる ・なお、ArrayListクラスでは格納により型情報が失われてしまい、キャストが必要だが、List<T>クラスでは 不必要になり、使いやすい。 ・List<T>クラスには、ArrayListクラスと同様に、格納用のAddメソッド、要素数を返すCountプロパティ、 整列するSortメソッドなどがある。 ・利用には、using System.Collections.Generic; を指定すると便利
p.368 list01.cs
//p.368 list01.cs
using System;
using System.Collections.Generic; //List<T>用
class list01 {
public static void Main() {
bool bEnd = false; //終了フラグをオフ
//ジェネリックコレクションクラスList<T>のオブジェクトを生成
List<int> mylist = new List<int>(); //型パラメータで整数型を指定
while (true) { //無限ループ
Console.Write("Data = ");
string strData = Console.ReadLine();
if (!Char.IsDigit(strData[0])) { //先頭文字が数字ではない?
bEnd = true; //終了フラグをオン
} else {
mylist.Add(int.Parse(strData)); //整数化してリストに格納
}
if (bEnd) { //終了フラグオン?}
break; //ループを抜ける
}
}
Console.WriteLine(); //改行
for (int i = 0; i < mylist.Count; i++) { //全要素について繰返す
Console.WriteLine("[{0}] {1}", i, mylist[i]);
}
Console.WriteLine(); //改行
mylist.Sort(); //昇順に整列
for (int i = 0; i < mylist.Count; i++) { //全要素について繰返す
Console.WriteLine("[{0}] {1}", i, mylist[i]);
}
}
}
p.369 コレクションクラスの初期化
・ジェネリッククラスであるかどうかとは無関係で、コレクションクラスの初期化にはコレクション初期化子が利用可能
・通常のクラスの場合の書式: クラス名 参照変数 = new クラス名{値,…}
・ジェネリッククラスの場合の書式: クラス名<型> 参照変数 = new クラス名<型>{値,…}
p.369 list02.cs
//p.369 list02.cs
using System;
using System.Collections.Generic;
class list02 {
public static void Main() {
List<string> names = new List<string> { "一郎", "二郎", "三郎" };
foreach (string s in names) { //格納されている全要素について繰返す
Console.WriteLine(s);
}
}
}
アレンジ演習:p.369 list02.cs
・ジェネリッククラスではないArrayListクラスにしてみよう
作成例
//アレンジ演習:p.369 list02.cs
using System;
using System.Collections; //ArrayList用
class list02 {
public static void Main() {
ArrayList names = new ArrayList{ "一郎", "二郎", "三郎" }; //コレクション初期化子
foreach (var s in names) { //格納されている全要素について繰返す
Console.WriteLine(s);
}
}
}
p.370(オブジェクト初期化子)
・テキストには説明されていないが、p.370 list03.csは、オブジェクト初期化子で初期化したオブジェクトを
コレクション初期化子の要素としている。
・オブジェクト初期化子は「データメンバ名 = 値」の書式により、オブジェクトの初期値を設定できる仕掛け
・ジェネリッククラスであるかどうかとは無関係
・書式: クラス名 参照変数 = new クラス名{メンバ名 = 値; …};
・なお、オブジェクト初期化子として用いるデータメンバは基本的にpublicである必要がある。
・ただし、publicなプロパティを経由するなら問題ない。
p.370 list03.cs
//p.370 list03.cs
using System;
using System.Collections.Generic;
class BOOK {
public string title; //コレクション初期化子で扱うデータメンバ
public string author;
public decimal price;
}
class list03 {
public static void Main() {
List<BOOK> mybook = new List<BOOK> { //全体はコレクション初期化子
new BOOK {title = "我が輩は猫である",
author = "夏目漱石",
price = 1050}, //それぞれ扱うがオブジェクト初期化子
new BOOK {title = "雲の階段",
author = "渡辺淳一",
price = 1600}, //それぞれがオブジェクト初期化子
new BOOK {title = "こころ",
author = "夏目漱石",
price = 1200} //それぞれがオブジェクト初期化子
};
Console.WriteLine("----蔵書一覧----");
foreach (BOOK b in mybook) { //全要素について繰返す
Console.WriteLine("{0}, {1}, {2}円", b.title, b.author, b.price);
}
}
}
アレンジ演習:p.370 lit03.cs
・3つあるBOOKオブジェクトを、予め、オブジェクト初期化子で初期化しておこう ・これらをコレクション初期化子でList<T>に格納しよう ・また、データメンバを全てprivateにし、これらの為のをpublicなプロパティを追加しよう (適当なルールを仕掛けておくと良い)
作成例
//アレンジ演習:p.370 list03.cs
using System;
using System.Collections.Generic;
class BOOK {
string title; //コレクション初期化子で扱うデータメンバ
string author;
decimal price;
public string T { set { title = value; } get { return title; } } //プロパティ
public string A { set { author = value; } get { return author; } }
public decimal P { set { if (value >= 0) price = value; } get { return price; } }
}
class list03 {
public static void Main() {
BOOK x = new BOOK {T = "我が輩は猫である", A = "夏目漱石", P = 1050}; //オブジェクト初期化子
BOOK y = new BOOK {T = "雲の階段", A = "渡辺淳一", P = 1600}; //オブジェクト初期化子
BOOK z = new BOOK {T = "こころ", A = "夏目漱石", P = 1200}; //オブジェクト初期化子
List<BOOK> mybook = new List<BOOK> { x, y, z }; //全体はコレクション初期化子
Console.WriteLine("----蔵書一覧----");
foreach (var b in mybook) { //全要素について繰返す
Console.WriteLine("{0}, {1}, {2}円", b.T, b.A, b.P); //プロパティ経由に
}
}
}
p.371 ジェネリッククラスと継承
・ジェネリッククラスの継承には、型パラメータの指定方法に伴う制限がある
・ジェネリッククラスの型パラメータに具体的な型を指定した状態で継承の基本クラスにできる
・書式: class 派生クラス : 基本ジェネリッククラス<型名> {…}
・これをクローズ構築型といい、派生クラスは通常クラスでもジェネリッククラスでも良い
・ジェネリッククラスの型パラメータが型パラメータのままの状態で継承の基本クラスにできる
・書式: class 派生クラス<型パラメータ> : 基本ジェネリッククラス<型パラメータ> {…}
・これをオープン構築型といい、派生クラスはジェネリッククラスでなければならない
・オープン構築型では型パラメータの基本クラスからの引継ぎが行われる
p.371 generic03.cs
//p.371 generic03.cs
using System;
class MyClass<T> { //ジェネリック基本クラス
public T x;
}
class MyClass2 : MyClass<int> { //クローズ構築型を継承
//ここに「public T x;」があり型が入って「public int x;」とみなされる
public void show() {
Console.WriteLine(x);
}
}
class generic03 {
public static void Main() {
MyClass2 mc = new MyClass2(); //型パラメータは不要
mc.x = 10; //クローズ構築型継承によりint型になっている
mc.show();
}
}
アレンジ演習:p.371 generic03.cs
・クローズ構築型では、派生クラスもジェネリッククラスで良いことを確認しよう ・MyClass2クラスを、MyClass2<T>ジェネリッククラスにして、T型のデータメンバyを追加する ・showメソッドでyも表示するようにしよう ・なお、MyClass<T>の型パラメータTは無関係になることも確認しよう
作成例
//アレンジ演習:p.371 generic03.cs
using System;
class MyClass<T> { //ジェネリック基本クラス
public T x;
}
class MyClass2<T> : MyClass<int> { //【変更】クローズ構築型を継承するジェネリッククラス
//ここに「public T x;」があり型が入って「public int x;」とみなされる
public T y; //【追加】
public void show() {
Console.WriteLine("x = {0}, y = {1}", x, y); //【変更】
}
}
class generic03 {
public static void Main() {
MyClass2<string> mc = new MyClass2<string>(); //【変更】型パラメータは不要
mc.x = 10; //クローズ構築型継承によりint型になっている
mc.y = "Shar"; //【追加】
mc.show();
}
}
p.372(オープン構築型)
・「class 派生クラス<型パラメータ> : 基本ジェネリッククラス<型パラメータ>」とすることで、型パラメータが引き継がれる
p.372 generic04.cs
//p.372 generic04.cs
using System;
class MyClass<T> { //ジェネリック基本クラス
public T x;
}
class MyClass2<T> : MyClass<T> { //オープン構築型を継承するジェネリッククラス
//ここに「public T x;」があるとみなされる
public void show() {
Console.WriteLine(x);
}
}
class generic04 {
public static void Main() {
MyClass2<int> mc = new MyClass2<int>(); //型パラメータが必要
mc.x = 2; //クローズ構築型継承によりint型になっている
mc.show();
MyClass2<string> mc2 = new MyClass2<string>(); //型パラメータが必要
mc2.x = "test"; //クローズ構築型継承によりstring型になっている
mc2.show();
}
}
p.373(複数の型パラメータを持つジェネリッククラスの継承)
・複数の型パラメータについて、すべてに具体的な型を指定すればクローズ構築型になる ・1つでも型パラメータのままにすれば、オープン構築型になる ・この時、一部の型パラメータについて具体的な型を指定することもできる
作成例
//p.373 generic05.cs
using System;
class MyClass<T, U> { //複数の型パラメータを持つジェネリック基本クラス
public T x;
public U y;
}
class MyClass2<T> : MyClass<T, int> { //共有されていない型は明示:オープン構築型
//ここに「public T x;」があるとみなされる
//ここに「public U y;」があり、「public int y;」とみなされる
public void show() {
Console.WriteLine("x = {0}, y = {1}", x, y);
}
}
class generic05 {
public static void Main() {
MyClass2<string> mc = new MyClass2<string>(); //型の指定が必要
mc.x = "cat"; //生成時にstring型にしたもの
mc.y = 20; //継承時にint型にしたもの
mc.show();
}
}