【ゲーム開発のためのC#入門講座・応用学習編】名前空間で重複を避けよう【#6】

2022-02-204.0_C#応用学習編

Visual Studio Codeで環境構築された方へ

本記事はVisual Studio想定であるため、Visual Studio Codeで環境構築された方は下記をご参照下さい。

クラスの基礎はばっちり!

ここまでオブジェクト指向の根幹を支える技術「クラス」について、扱い方やメンバー変数、コンストラクタなどを学んできました。

これでクラスの基本的な使い方はばっちりです。

ただ、オブジェクト指向では基本的に「1クラス=1スクリプトファイル」で管理します。これまでは説明を省くためにひとつのスクリプトファイルにすべてまとめてしまっていましたが、ファイルが肥大化してくるとコードを探し出すのも一苦労ですし、部分的な再利用もしにくくなってしまいます。

ということで、複数ファイルによるプログラム構築を行うこととしましょう。

新しいスクリプトファイルを作成しよう

練習ということで、今回は新しいプロジェクトを作成しましょう。

以降の記載と全く同じにするのであれば、プロジェクト名は「Csharp4-6」としてください。

それでは、まず新しいスクリプトファイルを作成しましょう。

「Visual Studio」のソリューションエクスプローラでプロジェクト名を右クリックしてください。その上で、「追加」という選択肢にカーソルを合わせ、「クラス」という選択肢を押下してください。

すると下記のような「クラス」の追加画面が表示されるため、作成したいクラス名を入力します。今回は演習ということで「Random」と入力の上、画面右下の追加ボタンを押下しましょう。

新しいファイルが生成され、下記コードが初期設定で表示されていれば成功です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace Csharp4_6
{
    internal class Random
    {
    }
}

ただでさえ専門用語が多いのに、「using」とか「namespace」とか「internal」とか、訳が分からない単語がまた増えてきましたね……(ヽ"ω`)ゲッソリ

だからプログラミング学習はハードルが高いって言われるんだよぉぉぉと愚痴も零したくなりますが、「namespace」については今回、「using」については次回解説します。「internal」については応用拡張編で解説予定ですので、一旦スルーしていただければと思います。

別のスクリプトファイルに定義したクラスを使おう

早速「Program.cs」の方で、新しく作成した「Random」クラスを使ってみましょう。

画面上部のタブで切り替えるか、ソリューションエクスプローラーで「Program.cs」をダブルクリックしてください。

続いて、初期設定されているコードを消して、下記のコードを実装しましょう。

Random random = new Random();
int result = random.Next(10);
Console.WriteLine(result);

実行してランダムな数値がコンソール画面に出力されれば成功です。

これで無事、別のスクリプトファイルに定義したクラスを使うことができましたね!

めでたし、めでたし……。

……。

え、「Random」クラスに「Next」なんてメソッドは実装していない?

というか、初期状態のままだからメソッドは何もないはず?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace Csharp4_6
{
    // ↓メソッドなんてひとつもないよ!
    internal class Random
    {
    }
}

そうですね。なので、先程のプログラムで作成されたインスタンスは実は自分達で作った「Random」クラスではなく、Microsoftの誰かさんが作ってくれた「Random」クラスになります。

// ↓この「Random」はMicrosoftの誰かが作ってくれたクラスであって、
//  先程自分達が作成した「Random」クラスではないよ!
Random random = new Random();
int result = random.Next(10);
Console.WriteLine(result);

うーん、名前がかぶっているからコンピュータが誤認してしまったようです。自分達の「Random」クラスを使ってもらうにはどうすればよいのでしょう?

あいつもこいつも作りたいクラスがある

こんな風に、自分が作成したい名前のクラスが実は他の誰かの手によって既に作られていた、なんてことは十分考えられます。オブジェクト指向の歴史は比較的浅いとはいえ、無数のプログラマーがいて、日々新しいクラスが作成されている訳ですからね。

しかしこれってコンピュータの立場で考えるとすごく困ったことですよね。「new Random()」という命令を受けた時に、果たしてどの「Random」クラスのインスタンスを生成すればいいのかわからない訳ですから。

とはいえ、じゃあ同じ名前のクラスは作成できないことにしよう、なんてルールにしてしまうと、早い者勝ちでほとんどの名前が使えないことになってしまいます。

めちゃくちゃ不便ですよね。

そこで、同じ名前のクラスを複数作れる方法が考案されました。

それが名前空間です。

名前空間を設定しよう

名前空間って抽象的でわかりにくいんですけど、やっていることはすごく単純です。

ようはクラスの所属するグループを決められる機能なんですね。

例えばAさんが作った「Random」は「A」というグループに属している、Bさんが作った「Random」は「B」というグループに属しているとします。

これなら、例えクラス自体は同じ「Random」という名前であったとしても、「AグループのRandom」だとか「BグループのRandom」といった指定ができますよね。

コンピュータ君も、どの「Random」のことだろうと悩まずに済む訳です。

これを定義しているのが先程出来てきた「namespace」というキーワードです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
// ↓名前空間を定義しているよ!
namespace Csharp4_6
{
    internal class Random
    {
    }
}

クラスを作成した時はプロジェクト名がデフォルトで設定されますが、自由に変更することが可能です。

試しに「Number」に変更してみましょう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
// ↓名前空間を「Number」に変更したよ!
namespace Number
{   
    internal class Random
    {
    }
}

そして「Program.cs」のコードを下記のように修正してみてください。

Number.Random random = new Number.Random();
int result = random.Next(10);
Console.WriteLine(result);

このように「名前空間.クラス」と記述することで、どの名前空間に属しているクラスを扱いたいのか、指定することができます。

これで今度こそ、自分達の作った「Random」クラスのインスタンスを作成する命令として認識してもらえるようになりました。

その証拠に、「Next」というメソッドに赤い波線が引かれているかと思います。該当箇所にカーソルをあてるか、画面下部のエラーマークをクリックすると、現在発生しているエラー内容が表示されます。

自分達の作った「Random」クラスには「Next」なんてメソッドはありませんから、エラー内容は正しいですね。

名前空間は入れ子にできる

名前空間は入れ子にすることができます。

グループの中にさらに細かいグループを持てる、ということですね。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
// ↓Yuumeというグループの中に、
namespace Yuume
{
    // ↓さらにNumberというグループがあり、
    namespace Number
    {   
        // ↓そこに所属しているクラスだよ!
        internal class Random
        {
        }
    }
}

基本的に名前空間は、作者・会社名だったり所属しているクラスの性質を表す単語だったりを指定します。

なぜなら、

  • 作者名や会社名などのユニークな名称を使うことで、名前空間までかぶってしまうリスクを下げられる(名前空間までかぶると本当に詰み)
  • 性質の近いものをまとめた単語なら、所属しているクラスが想像しやすくなる

という恩恵が得られるからです。

入れ子構造の名前空間に属するクラスを対象とする場合は「.」で名前空間を繋ぎます。

Yuume.Number.Random random = new Yuume.Number.Random();

Unityでの活躍ポイント

Unityの場合、アセットストアと呼ばれる場所で他の人が作ったスクリプトを購入することができます。こういった時に名前空間の設定がないと、再利用しようとしたら名前がかぶって使えないなんてことが起きてしまうんですね。

Unityの公式マニュアルでも解説ページが1ページ用意されています。

表現が分かり辛いので無理に読まなくてOKですが、色んな人がクラスを再利用するために重要な機能なんだなということがご理解いただければ幸いです。

実践演習

それでは実際に新規のスクリプトファイル生成と名前空間設定をしてみましょう。

演習①新規のスクリプトファイルを生成しよう!

今回の記事を見直しながら、新しいクラス「Pikachu」を作成してください。

演習②名前空間を設定しよう!

演習①で作成したクラス「Pikachu」が、「Nintendo」の「Pokemon」という名前空間に属するよう、名前空間を追加・変更してあげてください。

答え合わせ

演習①②合わせた答えとなります。

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

namespace Nintendo
{
    namespace Pokemon
    {
        internal class Pikachu
        {
        }
    }
}

まとめ

  • オブジェクト指向では基本的に「1クラス=1スクリプトファイル」で管理する
  • 名前空間とはクラスの属するグループを定義できる機能。この機能のおかげで同名のクラスがあっても使い分けることができる
  • 名前空間は入れ子にすることができる
  • 作者・会社名だったり所属しているクラスの性質を表す単語を設定することが多い

次回は名前空間と関連性の深い「using」について学習します。お楽しみに!

それでは、今回もお疲れ様でした!

また次の記事でお会いしましょう!

お借りした素材一覧

この記事では下記サイト様の素材をお借りしています。

ありがとうございました!

かわいいフリー素材集 いらすとや (irasutoya.com)

Posted by yuumekou