++C++; // 未確認飛行 C

Google
Web ufcpp.net

名前空間

目次

キーワード

概要

名前空間(name space)とは、 ファイルを種類ごとにフォルダに分けて管理するのと同じように、 クラスを種類ごとに分けて管理するための機構です。

名前空間とは

ウェブページを作成する場合、コンテンツごとにフォルダに分けて管理すると、サイトの管理がしやすくなります。 例えば、うちのサイトの場合、以下のようなフォルダ構成になっています。 (注:今は構成が変わっています。昔はこういう構成でした。)

/--+-- memo           (ひとくちメモの過去ログ)
   |
   +-- csharp         (このコーナー)
   |
   +-- study-------+  (院試勉強まとめ用)
                   |
                   +-- em      (電磁理論)
                   |
                   +-- math    (数学)

そして各フォルダの中にhtmlや画像ファイルがあります。 このようにコンテンツごとに分けることで、どこにどのファイルがあるのかが分かりやすくなりますし、 それぞれのフォルダに同じ名前のファイル(例えばindex.htmlやback.png)があっても問題はおきません。

プログラムを作成する場合でも、プログラムの規模が大きくなってきて、クラスの数が多くなってくると、 クラスを関連性のあるもの同士まとめて管理するような仕組みが必要になってきます。 そのような、クラスを階層的に分類するための機構が名前空間です。

例として、.NET frameworkの標準クラスライブラリを見てみましょう。 .NET frameworkの標準クラスライブラリ中のクラスの大半はSystemという名前空間に属しています。 System名前空間の下に、TextIODrawingなどの名前空間があります。 以下に、名前空間の階層構造と、各名前空間の説明および名前空間に属するクラスの一部を簡単に示します。

System --+
         |
         +-- IO
         |   (ファイル入出力。File や Directory などが属する。)
         +-- Text -----+  (文章処理。Encoding などが属する。)
         |             |
         |             +-- RegularExpressions
         |                 (正規表現。Regex や Match などが属する。)
         |
         +-- Drawing --+  (GUI処理。Image や Font や Icon などが属する。)
                       |
                       +-- Imaging
                       |   (画像処理。ImageFormat や Encoder などが属する。)
                       +-- Printing
                           (印刷。PrintController などが属する。)

このように階層的に名前を管理することで、例えば、System.Text.Encodingクラス(Windowsのファイルシステムではフォルダの区切りに「 \ 」を使いますが、C#の名前空間の区切りには「 . 」を使います)は画像や音声のエンコード形式ではなくテキストの文字コードだと容易に見当が付きます。

名前空間の使い方

今度は具体的に名前空間を使う方法を見ていきましょう。 ここでは例として、学校の課題で文字列クラス、リストクラス、可変長配列クラス、画像クラスを作れといわれたとします(これらのものは、標準ライブラリに初めから用意されていますが、プログラムの勉強のためにわざわざ自作してみることになった)。

まず、課題を出された各人の作ったクラスの名前が重ならないように、それそれ自分の名前を使って名前空間を作ります。 文字列クラスStringはそのすぐ下に作りましょう。 そして、リストクラスListと可変長配列クラスVectorは、名前空間Collectionsを作ってその下に、画像クラスImageは名前空間Drawingを作ってその下に作ることにします。 階層構造は以下のようになります。

Iwanaga --+-- String                    (文字列クラス)
          |
          +-- Collections --+-- List    (リストクラス)
          |                 |
          |                 +-- Vector  (可変長配列クラス)
          |
          +-- Drawing --------- Image   (画像クラス)

このような構造の名前空間を作るためには以下のように書きます。

namespace Iwanaga
{
  class String{// String の内容}

  namespace Collections
  {
    class List{// List の内容}

    class Vector{// Vector の内容}
  }

  namespace Drawing
  {
    class Image{// Image の内容}
  }
}

名前空間を定義するためには namespace というキーワードを使います。 そしてその後に続く {} の中で定義したクラスや名前空間はすべてその名前空間に属することになります。 また、以下のように書いてもこれとまったく同じ意味になります。

namespace Iwanaga
{
  class String{// String の内容}
}

namespace Iwanaga.Collections
{
  class List{// List の内容}
}

namespace Iwanaga.Collections
{
  class Vector{// Vector の内容}
}

namespace Iwanaga.Drawing
{
  class Image{// Image の内容}
}

つまり、名前空間を2つ以上の場所に分けて書くこともできますし、 「 . 」で区切ることで階層構造を指定できます。

次に、名前空間中に定義したクラスを参照する方法を説明します。 名前空間中に定義したクラスは、以下のように、階層構造を「 . 」で区切って指定することで参照できます。

class NameSpaceTest
{
  public static void Main()
  {
    Iwanaga.String str = new Iwanaga.String("test");

    Iwanaga.Collections.List list = new Iwanaga.Collections.List();
    Iwanaga.Collections.Vector vec = new Iwanaga.Collections.Vector();

    Iwanaga.Drawing.Image image = new Iwanaga.Drawing.Image("back.png");
  }
}

Iwanaga.Collections.Vectorというように、名前空間をすべて指定した形式の名前を完全修飾名と言います。

また、いちいち完全修飾名を書かなくても済むように、usingディレクティブというものが用意されています。

using Iwanaga; // 名前空間 Iwanaga 内にあるクラスを修飾名なしで使えるようになる

class NameSpaceTest
{
  public static void Main()
  {
    String str = new String("test"); // Iwanaga. が要らない

    Drawing.Image image = new Drawing.Image("back.png");
  }
}
using Iwanaga;
using Iwanaga.Collections;
using Iwanaga.Drawing;

class NameSpaceTest
{
  public static void Main()
  {
    String str = new String("test");     // Iwanaga. が要らない

    List list = new List();              // Iwanaga.Collections も要らない
    Vector vec = new Vector();

    Image image = new Image("back.png"); // Iwanaga.Drawing. も要らない
  }
}

先頭の using から始まる行がusingディレクティブです。 このように、usingディレクティブを使うことでコードの入力手間を省くことが出来ます。

エイリアス

先ほど自作したStringのテストのために、比較対象として.NET frameworkに標準で用意されているSystem.Stringクラスを同時に使用したいとします。 もちろん、Iwanaga.Stringというように完全修飾名を用いれば、System.Stringと共存可能なのですが、エイリアス(alias:別名付け)という機能を使うことでも共存させることが出来ます。

エイリアスは以下のような書き方をします。

using MyString = Iwanaga.String;

名前空間の先頭でこのような宣言をすることで、その名前空間中ではMyStringと書くことでIwanaga.Stringを参照することが出来ます。

using System;
using MyString = Iwanaga.String;           // クラスのエイリアス
using MyCollections = Iwanaga.Collections; // 名前空間のエイリアスも作れる

class NameSpaceTest
{
  public static void Main()
  {
    String str = new String("test");
    //↑ System.String が参照される
    MyString str = new MyString("test");
    //↑ Iwanaga.String が参照される
    MyCollections.List list = new MyCollections.List();
    //↑ Iwanaga.Collections.List が参照される
  }
}

サンプル

using System;

/// <summary>
/// 自作クラス用の名前空間
/// </summary>
namespace Iwanaga
{
  /// <summary>
  /// 数学関数の自作
  /// </summary>
  public class Math
  {
    /// <summary>
    /// sin(x) の値を求める。
    /// この実装は甘い。
    /// 入力できる値は-0.1~0.1程度で、精度も4桁程度。
    /// </summary>
    public static double Sin(double x)
    {
      double xx = -x*x;
      double fact = 1;
      double sin = x;

      for(int i=0; i<100; ++i)
      {
        fact *= i; ++i; fact *= i; ++i;
        x *= xx;
        sin += x / fact;
      }
      return sin;
    }//Sin
  }//class Math
}//namespace Iwanaga

namespace Sample
{
  using MyMath = Iwanaga.Math;

  class NameSpaceSample
  {
    public static void Main()
    {
      Console.Write("   x, System.Math.Sin(x), Iwanaga.Math.Sin(x)\n");
      for(int i=0; i<10; ++i)
      {
        double x = 0.01 * i;

        double y = Math.Sin(x);   // System.Math.Sin呼び出し
        double z = MyMath.Sin(x); // Iwanaga.Math.Sin呼び出し

        Console.Write("{0:f2},           {1:f6},            {1:f6}\n", x, y, z);
      }
    }
  }//class NameSpaceSample
}//namespace Sample
   x, System.Math.Sin(x), Iwanaga.Math.Sin(x)
0.00,           0.000000,            0.000000
0.01,           0.010000,            0.010000
0.02,           0.019999,            0.019999
0.03,           0.029996,            0.029996
0.04,           0.039989,            0.039989
0.05,           0.049979,            0.049979
0.06,           0.059964,            0.059964
0.07,           0.069943,            0.069943
0.08,           0.079915,            0.079915
0.09,           0.089879,            0.089879

エイリアス修飾子

Ver. 2.0

前節で説明したとおり、 名前空間にはエイリアス(別名)を付けられます。

例えば、以下のように、ちょっと長めの名前空間名 Iwanaga.Test.Utilities に、 短いエイリアス Util を付けたとします。

namespace Iwanaga.Test.Utilities
{
  class Image {}
}

namespace TestNamespace
{
  using Util = Iwanaga.Test.Utilities; // エイリアスをつける。

  class Program
  {
    static void Main(string[] args)
    {
      Util.Image img = new Util.Image();
    }
  }
}

このコード自体には特に問題もなく、ちゃんとコンパイルが通ります。 ところが、このプログラムを修正していくうちに、ちょっとした問題が生じる可能性があります。 例えば、複数人で開発しているものとして、 自分以外の誰かが、TestNamespace 内に Util というクラスを作ってしまったとしましょう。

namespace Iwanaga.Test.Utilities
{
  class Image {}
}

namespace TestNamespace
{
  using Util = Iwanaga.Test.Utilities;

  class Program
  {
    static void Main(string[] args)
    {
      Util.Image img = new Util.Image();
    }
  }

  class Util {} // Util クラスを追加。エラーになる。
}

たったこれだけでこのコードはコンパイルエラーを起こします。 (エイリアス Util がクラス Util と衝突しましたと怒られるか、 Util と言う名前は既に存在しますと怒られるはず。)

この問題を緩和するため、C# 2.0 では、エイリアス修飾子というものが追加されました。 エイリアス修飾子は、Alias.Class という書き方の代わりに、 Alias::Class と言うように、: を2つ付けます。 このエイリアス修飾子 :: は、基本的には . と同じ結果を生みますが、 ただ、エイリアスの後ろにしか付けられないという制限があります。 このため、:: の付いている部分の直前はエイリアスであることが確定し、 エイリアスと同名のクラスが追加されても混乱が起こりません。

namespace Iwanaga.Test.Utilities
{
  class Image {}
}

namespace TestNamespace
{
  using Util = Iwanaga.Test.Utilities;

  class Program
  {
    static void Main(string[] args)
    {
      Util::Image img = new Util::Image();
      //↑ この Util はエイリアスの Util とみなされる。
    }
  }

  class Util {} // Util と同名のクラスがあっても OK。
}

外部エイリアス

Ver. 2.0

C# 2.0 では、using を使ってエイリアスを定義する代わりに、 コンパイルオプションでエイリアスを付けることが可能になりました(外部エイリアス)。

外部エイリアスを使うにはまず、 ソースファイル中に extern alias という宣言を書きます。

extern alias X;

class Program
{
  static void Main(string[] args)
  {
    X::A a = new X::A();
  }
}

そして、ソースファイルのコンパイル時に、 以下のようなオプションを追加します。

csc /r:X=Iwanaga.dll Test.cs

これで、Iwanaga.dll というライブラリ中で定義された A というクラスを、 X::A という名前で参照できるようになります。

Transtation into English

[お問い合わせ](q)