名前空間

名前空間とは

例えばコンソール画面に文字列を表示するためにはConsole.WriteLineメソッドを使用します。
メソッド名自体は「WriteLine」なのですが、C#のソースコード上に単に「WriteLine」を記述してもメソッドを実行することはできません。
「Console.WriteLine」という記述は「Console」というフォルダ内にある「WriteLine」ファイルを実行する、というのと似ています。

「Console」フォルダ内には「WriteLine」ファイル以外にもたくさんのファイルが含まれています。
「Console」フォルダ自体もさらに別の上位のフォルダに格納されています。

このファイルとフォルダのような階層的な構造をコード上で表現するのが名前空間です。

■名前空間のイメージ
名前空間のイメージ

名前空間の階層構造は.(ドット)記号で区切って表します。
パソコンのフォルダ構造の区切り文字に「/(スラッシュ)」や「\(バックスラッシュまたは円記号)」を使用するのと意味は同じです。

usingディレクティブ

上記の画像の通り、コンソール画面に文字列を出力する「WriteLine」メソッドは、正しくは「System.Console.WriteLine」という場所に存在します。
しかし、今まで説明してきたコード中では「Console.WriteLine」という形で実行できています。
これを可能にしているのがコード先頭のusingディレクティブです。

以下はVisual Studioでプロジェクトを作成した時に自動的に生成されるコードです。
(.Net Framework4.5)

.NET6.0から、自動生成されるコードにusingディレクティブは記述されなくなっています。
これについては後述します。


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

//ここまでがusingディレクティブ

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("abc");
        }
    }
}

usingディレクティブは名前空間の指定を省略して記述できるようにするものです。
先頭のusing System;は「"System"内に存在するクラスを記述する場合は、"System"を省略して記述を可能にする」という効果があります。

仮にusing System;をコードから削除してみると、Console.WriteLineの箇所でエラーとなります。


//using System; //←コメントアウトしてみる
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //エラー
            Console.WriteLine("abc");
        }
    }
}

Visual Studioの場合は「Console」の下に赤線が引かれて「Consoleが見つからない」というエラーが表示されます。

これは「Console」の機能が無効になったわけではなく、見つからない(どこにあるのかが分からない)というだけです。
以下のように場所を明確に記述すれば使用することができます。


//using System; //←コメントアウトしてみる
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //「System」から記述する
            System.Console.WriteLine("abc");
        }
    }
}

このような、usingディレクティブによる省略形を使用しない記述を完全修飾名といいます。

「System」は名前空間ですが、「Console」は名前空間ではなくクラス名です。
WriteLineメソッドは正確には「System名前空間に属する、Consoleクラスの中に定義されているメソッド」となります。
usingディレクティブに指定できるのは「名前空間」なので、例えば「using System.Console;」と記述してこの部分を省略して書けるようにすることはできません。

暗黙的なusingディレクティブ

.NET6.0以降でプロジェクトを作成すると、自動生成されるコードにはusingディレクティブは記述されません。
これは暗黙的なusingディレクティブというVisual Studioの機能によるもので、コンソールアプリケーションの場合は以下のusingディレクティブが自動的に有効な状態になります。
(読み込まれる名前空間は今後のバージョンによって変更される可能性はあります)


using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

暗黙的なusingディレクティブの有効/無効は「プロジェクトのプロパティ」から変更できます。

プロジェクトのプロパティを開く
暗黙的なglobal usingの設定

上記画像の「暗黙的なglobal using」のチェックをオフにすると暗黙的なusingディレクティブは無効になります。
有効になるusingディレクティブはそのすぐ下に列挙されています。

暗黙的なglobal usingは、その名前の通りすべてのソースコードで有効になります。
ここの設定からusingディレクティブを追加することもできます。
もちろん、従来通り各コードの先頭でusingディレクティブを追加することもできます。

usingエイリアス

usingキーワードは他にも特定のクラスに対するショートカットを作る機能があります。
例えばファイル操作にはFileというクラスを使用しますが、FileクラスはSystem.IO名前空間に存在します。
なので、通常は以下のどちらかで記述します。


using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //完全修飾名でアクセス
            System.IO.File.ReadAllText("test.txt");

            //完全修飾名でアクセス
            IO.File.ReadAllText("test.txt");
        }
    }
}

using System;
using System.IO; //←これを追加

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //usingディレクティブにより省略形で書ける
            File.ReadAllText("test.txt");
        }
    }
}

毎回「System.IO.File.○○」と書くのはやや面倒ですから、省略して書ける後者のほうが便利です。
しかしこの記述をすると「System.IO」内にあるすべてのオブジェクトに対して省略形の記述が有効になります。

「System.IO.File」だけを省略形で記述したい場合は以下のようにします。


using System;

//「F」は「System.IO.File」の別名になる
using F = System.IO.File;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            F.ReadAllText("test.txt");
            //↑は↓と同じ意味
            System.IO.File.ReadAllText("test.txt");
        }
    }
}

このようにすると、コード中のFSystem.IO.Fileの別名として扱われます。
これをusingエイリアス(エイリアス)といいます。
エイリアス名は自由に付けることができます。

名前空間の定義

名前空間は自分で定義することもできます。
Visual Studioでコードを自動生成した時、プロジェクト名の名前空間が自動的に定義されています。


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

//↓これが名前空間の定義
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

名前空間の定義はnamespaceというキーワードで行います。
名前空間は「name space」の直訳です。

namespaceブロック内が新しい名前空間として定義されます。
自動生成される名前空間以外にも必要に応じて新しい名前空間を定義可能です。


using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //名前空間「Test」の中の「Program.number」にアクセス
            int num = Test.Program.number;

            Console.WriteLine(num);
            Console.ReadLine();
        }
    }
}

//「Test」という名前空間の定義
namespace Test
{
    class Program
    {
        public static int number = 1;
    }
}
1

自分で定義した名前空間へのアクセスの仕方も今までと同じです。

上記コードは「Program」というクラスが二つ存在しますが、それぞれ別の名前空間に定義されています。
名前空間はそれぞれで独立しているので、二重定義にはなりません。

名前空間は入れ子にして定義することもできます。


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int num1 = Test.AAA.Program.number; //1
            int num2 = Test.BBB.Program.number; //2
        }
    }
}

namespace Test
{
    namespace AAA
    {
        class Program
        {
            public static int number = 1;
        }
    }

    namespace BBB
    {
        class Program
        {
            public static int number = 2;
        }
    }
}

名前空間は同じ名前を重複して付けることができます。
重複というよりも複数に分割できる、といった方が正しいかもしれません。
これはソースコードを複数に分ける時などに使用します。


namespace Test
{
    class Program
    {
    }
}

namespace Test
{
    class Program2
    {
    }

    //同じ名前はダメ
    //class Program
    //{
    //}
}

コード上は分けられていても同じ名前空間内では同じ名前のオブジェクトは定義できません。
上記の例では上段の名前空間「Test」内に「Program」クラスがすでに定義されているので、下段の名前空間「Test」では「Program」クラスは定義できません。