テキスト篇:p.386「練習問題」から
ゲーム開発演習:画像位置の管理、自弾の発射 など
p.386 練習問題 ヒント
・p.368 list01.csを基にすると良い ・整列は不要になる ・受験者数、合計点数、平均値の表示を追加する ・入力終了条件を「整数以外」から「負の数」に変更する
作成例
//p.386 練習問題
using System;
using System.Collections.Generic; //Listクラス用
class prac15 {
public static void Main() {
int num = 0; //【追加】受験者数
int sum = 0; //【追加】合計点
List<int> mylist = new List<int>(); //型パラメータを与えてListオブジェクトを生成
while (true) { //無限ループ
Console.Write("Data = ");
int strData = int.Parse(Console.ReadLine()); //【変更】
if (strData < 0) { //負の数なら
break; //繰返しを抜ける
}
mylist.Add(strData); //【変更】リストに追加
num++; //【追加】受験者数カウント
sum += strData; //【追加】合計点に加算
}
Console.WriteLine("受験者数:{0}", num); //【追加】
Console.WriteLine("合計点数:{0}", sum); //【追加】
Console.WriteLine("平均値:{0}", (double)sum / num); //【追加】
}
}
第16章 名前空間、プリプロセッサ、属性など
p.387 名前空間
・ここまで作成したプログラムで「using」で指定してきた「System」「System.Collection.Generic」などは名前空間(Name Space) ・名前空間とは、定義の領域を定める仕掛けで、名前空間が異なれば同一名の定義が可能になり、名前の管理の効率が上がる ・異なる名前空間にあるものを用いるには「名前空間名.」を前置すれば良い
p.388 名前空間の定義
・プログラマが自前の名前空間を定義することもできる
・定義書式: namespace 名前空間名 {…}
・なお、名前空間が示されていない場合、無名の名前空間にあると見なされる
p.388 namespace01.cs
//p.388 namespace01.cs
using System;
namespace Cat { //名前空間「Cat」の定義
class Animal { //外部からはCat.Animalでアクセスできるクラス
public string name; //外部からはCat.Animalのnameでアクセスできるメンバ
public void show(){ //外部からはCat.Animalのshow()でアクセスできるメソッド
Console.WriteLine("猫の名前は{0}です", name);
}
}
}
namespace Dog {//名前空間「Dog」の定義
class Animal { //外部からはDog.Animalでアクセスできるクラス
public string name; //外部からはDog.Animalのnameでアクセスできるメンバ
public void show(){ //外部からはDog.Animalのshow()でアクセスできるメソッド
Console.WriteLine("犬の名前は{0}です", name);
}
}
}
class namespace01 { //無名の名前空間にあるクラス
public static void Main() {
Cat.Animal cat = new Cat.Animal(); //名前空間を指定してインスタンスを生成
cat.name = "タマ";
Dog.Animal dog = new Dog.Animal(); //名前空間を指定してインスタンスを生成
dog.name = "ポチ";
cat.show();
dog.show();
}
}
p.390 usingディレクティブ
・ソースファイルの冒頭または名前空間の冒頭に「using 名前空間;」を指定すると、その範囲内で「名前空間.」を省略できる ・ソースファイルの冒頭に指定すると全体で有効になるが、名前管理のトラブルに注意。 ※プロジェクトによっては自前の名前空間をusingディレクティブに指定することを禁止する場合がある ・名前空間の冒頭に指定するとその名前空間の中でのみ有効になる ・定義書式: using 名前空間名; ・別名を付ける為に利用ことも可能 ・定義書式: using 別名 = 名前空間名;
p.390 namespace02.cs
//p.390 namespace02.cs
using Cat; //usingディレクティブで「Cat.」の省略が可能
using D = Dog; //usingディレクティブで「Dog.」の別名「D.」を定義
namespace Cat { //名前空間「Cat」の定義
using System;
class Animal { //外部からはAnimalでアクセスできるクラス
public string name; //外部からはAnimalのnameでアクセスできるメンバ
public void show(){ //外部からはAnimalのshow()でアクセスできるメソッド
Console.WriteLine("猫の名前は{0}です", name);
}
}
}
namespace Dog { //名前空間「Dog」の定義
using System;
class Animal { //外部からはD.Animalでアクセスできるクラス
public string name; //外部からはD.Animalのnameでアクセスできるメンバ
public void show(){ //外部からはD.Animalのshow()でアクセスできるメソッド
Console.WriteLine("犬の名前は{0}です", name);
}
}
}
namespace MyNamespace {
class Namespace01 {
public static void Main() {
Animal cat = new Animal(); //usingによりCat.Animalが用いられる
cat.name = "タマ";
D.Animal dog = new D.Animal(); //usingによりDog.Animalが用いられる
dog.name = "ポチ";
cat.show();
dog.show();
}
}
}
p.392 名前空間のあいまいさ
・usingディレクティブの指定により、定義が重複し対象が特定できない場合、コンパイルエラーになる ・なお、usingディレクティブで別名を指定しても、元の名前を利用できる。 ※ 可読性が低下するので、指定したら用いることで統一すると良い
p.393 名前空間のネスト
・名前空間の中に名前空間を定義できる ・外部から内側の名前空間にあるものにアクセスするには「外側の名前空間名.内側の名前空間名.」を用いる ・なお、名前空間の定義を複数個所で行うこと=分割定義が可能。 ・テキストの「p.394 namespace03.cs」では、Cat名前空間内にCatクラスを定義しており、この重複は可能 ※ プロジェクトによっては禁止される場合があるので、ここではHouseCatクラスに変更している
p.394 namespace03.cs
//p.394 namespace03.cs
namespace Animal { //外側の名前空間定義
using System; //Animal名前空間内では「System.」は省略可
namespace Mammal { //内側の名前空間定義(外からはAnimal.Mammal)
namespace Cat { //さらに内側の名前空間定義(外からはAnimal.Mammal.Cat)
class HouseCat { //外からはAnimal.Mammal.Cat.HouseCatクラス
public string name;
public void show() {
Console.WriteLine("猫の名前は{0}です", name);
}
}
}
}
}
namespace MyNamespace { //名前空間定義
class Namespace03 {
public static void Main() {
//ネストした名前空間にあるクラスのインスタンスを生成
Animal.Mammal.Cat.HouseCat mycat = new Animal.Mammal.Cat.HouseCat();
mycat.name = "マイケル";
mycat.show();
//ネストしていない名前空間にあるクラスのインスタンスを生成
Animal.Dog mydog = new Animal.Dog();
mydog.name = "ポチ";
mydog.show();
}
}
}
namespace Animal { //Animal名前空間の定義の続き
class Dog { //外からはAnimal.Dogクラス
public string name;
public void show() {
System.Console.WriteLine("犬の名前は{0}です", name);
}
}
}
p.395(名前空間のネストの定義の省略記法)
・内側の名前空間は「namespace 名前空間名.名前空間名」と定義することもできる
・例: namespace A { namespace B {…} } ⇒ namespace A.B {…}
・ただし、外側や中間の名前空間に属するものがある場合は、別途、定義する必要がある
・例: namespace A{●; namespace B{■}} ⇒ namespace A{●} namespace A.B{■}
・テキストの「p.396 namespace04.cs」では、Dog名前空間内に「using System;」を指定しているのに
「System.Console.WriteLine」としており、この「System.」は不要
p.396 namespace04.cs
//p.396 namespace04.cs
namespace Animal { //名前空間定義
using System; //この名前空間定義内で有効(別途定義のネストの中では無効)
class Dog {
public string name;
public void show() {
Console.WriteLine("犬の名前は{0}です", name); //「System.」は不要
}
}
}
namespace Animal.Mammal.Cat { //ネストした名前空間定義
using System; // Animal名前空間でusing System;とあるがここでもう一度
class cat {
public string name;
public void show() {
Console.WriteLine("猫の名前は{0}です", name); //「System.」は不要
}
}
}
namespace MyNamespace {
class Namespace03 {
public static void Main() {
//ネストした名前空間にあるクラスのインスタンスを生成
Animal.Mammal.Cat.cat mycat = new Animal.Mammal.Cat.cat();
mycat.name = "マイケル";
mycat.show();
//ネストしていない名前空間にあるクラスのインスタンスを生成
Animal.Dog mydog = new Animal.Dog();
mydog.name = "ポチ";
mydog.show();
}
}
}
p.398 プリプロセッサ
・C/C++から引き継がれた機能で、コンパイラ(ビルド)における前処理=プリプロセスを指示できる機能 ・プリプロセッサの指示によってソースの書き換えを行い、書き換え結果がコンパイルされる ※ C/C++とは異なり、#defineによるマクロ定義や、#ifdefによるインクルードガードなどはC#では禁止 ・C#では、プリプロセッサの指示として「#define シンボル」「#if シンボル」「#endif」「#undef シンボル」などが指定可能 ・「#define シンボル」でシンボルを指定しておくと、「#if シンボル」と「#endif」で挟んだ行がコンパイル対象となる ・こうしておいてから「#define シンボル」を削除することで、上記をコンパイル対象から除外できる ・よって、コメントアウトによるコンパイル対象からの除外よりも可読性が高く、ミスを防止しやすい
p.399(プリプロセッサと論理演算子)
・「#if シンボル」において複数のシンボルを論理演算子を用いて指定できる ・「#if (シンボル① && シンボル②)」とすれば、両方のシンボルが指定時に対象になる ・「#if (シンボル① || シンボル②)」とすれば、どちらかのシンボルが指定時に対象になる ・また「#if (!シンボル)」とすれば、シンボルが指定されていない時に対象になる ・なお、シンボルは「#undef シンボル」の指定により無効化できる
p.400 preprocess01.cs
//p.400 preprocess01.cs
#define TEST //シンボルTESTの定義
using System;
class preprocess01
{
public static void Main()
{
#if TEST //シンボルTESTがあれば有効
Console.WriteLine("テストです");
#endif //範囲はここまで
#if (TEST && TEST2) //シンボルTESTとTEST2が共にあれば有効
Console.WriteLine("ここは、TESTとTEST2が定義されていないとコンパイルされません");
#endif //範囲はここまで
#if (TEST || TEST2) //シンボルTESTまたはTEST2があれば有効
Console.WriteLine("ここは、TESTかTEST2が定義されていればコンパイルされます");
#endif //範囲はここまで
#if TEST2 //シンボルTEST2があれば有効
Console.WriteLine("ここは、TEST2が定義されているとコンパイルされます");
#endif //範囲はここまで
}
}
アレンジ演習:p.400 preprocess01.cs
・「#if シンボル」のネストにより記述を簡略化できるか試してみよう
作成例
//アレンジ演習:p.400 preprocess01.cs
#define TEST //シンボルTESTの定義
using System;
class preprocess01
{
public static void Main()
{
#if TEST //シンボルTESTがあれば有効
Console.WriteLine("テストです");
#if TEST2 //しかもシンボルTEST2があれば有効(ネスト)
Console.WriteLine("ここは、TESTとTEST2が定義されていないとコンパイルされません");
#endif //範囲はここまで
#endif //範囲はここまで
#if (TEST || TEST2) //シンボルTESTまたはTEST2があれば有効
Console.WriteLine("ここは、TESTかTEST2が定義されていればコンパイルされます");
#if (!TEST) //シンボルTESTがなければ有効(ネスト)
Console.WriteLine("ここは、TEST2が定義されているとコンパイルされます");
#endif //範囲はここまで
#endif //範囲はここまで
}
}
p.401(その他のプリプロセッサディレクティブ)
・if文におけるelseにあたる「#else」ディレクティブを「#if シンボル」と「#endif」の間に1つだけ指定できる ・if文におけるelse ifにあたる「#elif シンボル」ディレクティブを「#if シンボル」と「#endif」の間または、 「#if シンボル」と「#else」の値に複数指定できる
p.402 Conditional属性
・メソッドの直前に記述することで、そのメソッドをコンパイル対象にするかどうかの条件を記述できる仕掛けがConditional属性
・Conditional属性をつけたメソッドを条件付きメソッドという
・書式: [Conditional("シンボル")] ※必ず独立した1行にすること
・利用には「using System.Diagnostics;」が必要
・条件付きメソッドに指定したシンボルが無い場合、条件付きメソッドを呼び出している部分もコンパイル対象から自動的に除外される
・そのため、条件付きメソッドは戻り値型がvoidで、オーバーライドしていないこと
※ なお、Conditional属性は複数行定義可能で「または」の関係になる
p.402 conditional01.cs
//p.402 conditional01.cs
#define TEST //シンボルTESTの定義
using System;
using System.Diagnostics; //Conditional属性用
class MyClass {
public string name;
[Conditional("TEST")] //TESTシンボルがあればshowメソッドは有効
public void show() { //条件付きメソッド
Console.WriteLine(name);
}
}
class conditional01 {
public static void Main() {
MyClass mc = new MyClass();
mc.name = "マイケル";
mc.show(); //条件付きメソッドを呼び出す(TESTシンボルがないと消える)
}
}