ネームスペース(Namespace)
C#は「コンポーネント指向のプログラム言語」
コンポーネント指向とは、すでに作成済みのクラスを持ち寄って、
それを利用する形でコーディングを行うこと
その際、まったく無関係に開発されたクラスを集めると、同じ名前のクラスが存在することがあり、
名前の衝突が発生する.
C#では、個々のクラスはより大きなnamespace(名前空間)に所属するものと考え、
namespaceを区別することで
同じ名前のクラスを使い分けることを可能とする。
POINT
namespace はネスト可能で . で区切ることができる。
POINT
namespace は複数にわけることもできる。
これによってソースコードを分離することができる。
namespace Space1
{
class Class1
{
public static void test(){}
}
}
namespace Space1
{
class Class2
{
public static void test(){}
}
}
POINT
次にこの namespace 内の名前を使うときに完全修飾名を記述するのは手間なので
using 宣言を利用することで 名前空間の指定を省略できる。
// namespace の省略があった場合に検索する namespace を指定する。
using System.IO;
// 別名をつけることもできる。
using MyClass = Space1.Sub1.Class1;
WARNING
using は、クラスやメソッドの内部には記述できない。
namespace”宣言直後などに記述すること。
namespace を有効にする. {} scope が考慮される.
{
// Block 内のみ有効. System namespace を利用する
using System;
class Foo {}
}
WARNING
ネームスペース直下の 変数宣言はダメ。
必ずクラス内にいれること。
namespace {
Form1 pForm;
}
namespace と using
namespaceやクラスの別名を宣言するusing
namespaceは便利な機能であるが
正面からこの機能を使うと、
何を指定するにもnamespaceの名前を使うことになり
表記が長くなる。
POINT
ソースコード上の狭い範囲に着目すれば
そこから参照するnamespaceの種類も限られている。
何も長い名前をいちいち書かなくても十分に分かりやすい
ソースを記述できる。
これを支援するために
C#にはusingという機能がある。
POINT
usingには
別名とデフォルトnamespaceを記述する機能がある。
別名機能は、namespaceや、
それに属するクラスに対して、
1つの名前を宣言する機能を提供している。
“ultra.super.special.long.long.name”というような長い
namespaceを頻繁に参照する場合に、もっと短い名前(例えば"longname)を付けることができる。
namespace Space1.Sub1
{
class Class1
{
public static void test()
{
Console.WriteLine("Space1.Sub1.Class1.test() called");
}
}
}
{
// 別名を与えた.
using MyClass = Space1.Sub1.Class1;
using MySpace1 = Space1.Sub1;
using MySpace2 = Space1;
// using Class1 = Space1.Sub1.Class1; // 下のClass1と名前が同じになるのでエラー
// 多重の using はできない.
// using MySpace3 = MySpace2.Sub1; // usingの対象にusingされたキーワードMySpace2は使用できないのでエラー
class Class1
{
static void Main(string[] args)
{
// Space1.Sub1.Class1.test() と同じ.
MyClass.test();
MySpace1.Class1.test();
MySpace2.Sub1.Class1.test();
}
}
}
ネストするnamespace
POINT
namespace をネストするのと
. 区切りにするのは意味としては同じ。
つまり、namespaceを宣言する際
ピリオド区切りの単一の名前で書いてもよいし、
ネストしたnamespaceとして宣言してもよい。
namespace Space1.Sub1
{
class Class1
{
public static void test()
{
Console.WriteLine("Space1.Sub1.test() called");
}
}
}
namespace Space2
{
namespace Sub1
{
class Class1
{
public static void test()
{
Console.WriteLine("Space2.Sub1.test() called");
}
}
}
}
{
// 呼び出す表記は同じになる
Space1.Sub1.Class1.test();
Space2.Sub1.Class1.test();
}
namespaceをわける。
POINT
namespaceの宣言は、
1つのブロックにまとめねばならないという制約はない
同じ名前のnamespaceの宣言が何回出現してもよい
namespace Test
{
class Class1
{
static void Main(string[] args)
{
Space1.Class1.test();
Space1.Class2.test();
}
}
}
同じ名前の複数の namespace にクラスを分けて記述できる。
POINT
1つのnamespaceの中に
同じ名前のクラスを2つ以上持つことはできない。
namespace をわけることは可能.
Space1という名前のnamespaceを宣言している。
同じように、
同じSpace1というnamespaceを宣言している。
2つに分かれているが
これは2つとも
同じ namespace の宣言の一部として機能する。
なぜなら、Space1というnamespaceの中では、
Class1という名前のクラスが宣言済みだからだ。
1つのnamespaceの中に
同じ名前のクラスを2つ以上持つことはできない。
namespaceの衝突
POINT:
using は、複数を指定できる。
ただし衝突には注意すること。
複数のクラス・ライブラリに含まれている
多くのメソッドを、短い名前で呼び出すことができる。
WARNING
何でもかんでも using すればよいというものではない。
usingで指定された複数の
namespace内に同じ名前のクラスがあり、
それを呼び出そうとするとコンパイラはエラーをだす。
namespace Space1.Sub1
{
class Class2
{
public static void test()
{
Console.WriteLine("Space1.Sub1.Class2.test()");
}
}
}
namespace Space2.Sub1
{
class Class2
{
public static void test()
{
Console.WriteLine("Space2.Sub1.Class2.test()");
}
}
}
{
// Space1.Sub1とSpace2.Sub1をusingで指定する。
// この2つのnamespaceに属するメソッドは
// namespace名なしで呼び出すことができる。
using Space1.Sub1;
using Space2.Sub1;
class Class1
{
static void Main(string[] args)
{
// Class2はあいまいな参照、というコンパイル・エラーになる
// どちらの Class2 か判別できない。
Class2.test();
}
}
}
エラーを解決するには呼び出したいクラスを明示する。
{
class Class2
{
public static void test()
{
Console.WriteLine("Space1.Sub1.Class2.test()");
}
}
}
namespace Space2.Sub1
{
class Class2
{
public static void test()
{
Console.WriteLine("Space2.Sub1.Class2.test()");
}
}
}
不完全なnamespaceとusing
usingはnamespaceのデフォルトを指定するが、
必ず完全なnamespaceでなければならない。
namespaceのネストの一部だけを指定できない。
namespace Space1.Sub1
{
class Class2
{
public static void test()
{
Console.WriteLine("Space1.Sub1.Class2.test()");
}
}
}
{
// Default namespace
// Space1 という namespace がデフォルトであると宣言する。
// これで Space1 内のクラスは宣言可能になる。
//
using Space1;
class Class1
{
static void Main(string[] args)
{
// Sub1 は namespace 名の一部を成す名前であって、
// 不完全なnamespace名を補うために宣言が使われることはない。
//
Sub1.Class2.test(); // Sub1 が見つからないというコンパイル・エラーになる
}
}
}
エラーなくすには
usingを使わずフルネームを書くか、
あるいは、usingで完全なnamespace名を指定する。
namespace ConsoleApplication23
{
using Space1.Sub1;
using Space2.Sub1;
// 短い名前を別名として定義することで指定を簡略化する
using MyClass2 = Space1.Sub1.Class2;
class Class1
{
static void Main(string[] args)
{
MyClass2.test();
}
}
}
2つの異なるnamespaceにある同じ名前のクラスの片方に別名をつけることにより
アクセスするクラスを特定する。
POINT
namespace や using の機能は、短いプログラムを書いているときにはありがたみを感じられないかもしれない。
しかし、膨大なクラス・ライブラリを活用するために、
usingの機能は不可欠である。
そのようなライブラリを整備するためには
namespaceは必須の機能。