次の方法で共有


14 名前空間

14.1 全般

C# プログラムは名前空間を使用して編成されます。 名前空間は、プログラムの "内部" 組織システムと、他のプログラムに公開されているプログラム要素を提示する "外部" 組織システムの両方として使用されます。

名前空間の使用を容易にするために、ディレクティブの使用 (§14.5) が用意されています。

14.2 コンパイル単位

compilation_unitは、0 個以上のextern_alias_directiveの後に 0 個以上のusing_directiveが続き、0 または 1 つのglobal_attributesの後に 0 個以上のnamespace_member_declarationが続きます。 compilation_unitは、入力の全体的な構造を定義します。

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

C# プログラムは、1 つ以上のコンパイル 単位で構成されます。 C# プログラムをコンパイルすると、すべてのコンパイル 単位が一緒に処理されます。 したがって、コンパイルユニットは、おそらく循環的に、互いに依存することができます。

コンパイル 単位の extern_alias_directiveは、そのコンパイル ユニットの using_directiveglobal_attributes 、および namespace_member_declarationに影響しますが、他のコンパイル ユニットには影響しません。

コンパイル ユニットの using_directiveは、そのコンパイル ユニットの global_attributesnamespace_member_declarationに影響しますが、他のコンパイル ユニットには影響しません。

コンパイル 単位の global_attributes (§22.3) を使用すると、ターゲット アセンブリとモジュールの属性を指定できます。 アセンブリとモジュールは、型の物理コンテナーとして機能します。 アセンブリは、物理的に分離された複数のモジュールで構成される場合があります。

プログラムの各コンパイル単位の namespace_member_declarationは、グローバル名前空間と呼ばれる 1 つの宣言空間にメンバーを提供します。

例:

// File A.cs:
class A {}
// File B.cs:
class B {}

この 2 つのコンパイル ユニットは、1 つのグローバル名前空間に貢献します。この場合、完全修飾名を持つ 2 つのクラス ABを宣言します。 2 つのコンパイル 単位は同じ宣言空間に影響するため、それぞれが同じ名前のメンバーの宣言を含む場合はエラーになります。

end の例

14.3 名前空間宣言

namespace_declarationは、キーワード名前空間の後に名前空間名と本文が続き、必要に応じてセミコロンで構成されます。

namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;

qualified_identifier
    : identifier ('.' identifier)*
    ;

namespace_body
    : '{' extern_alias_directive* using_directive*
      namespace_member_declaration* '}'
    ;

namespace_declarationは、compilation_unitの最上位の宣言として、または別のnamespace_declaration内のメンバー宣言として発生する可能性があります。 namespace_declarationcompilation_unitの最上位の宣言として発生すると、名前空間はグローバル名前空間のメンバーになります。 namespace_declarationが別のnamespace_declaration内で発生すると、内部名前空間は外部名前空間のメンバーになります。 どちらの場合も、名前空間の名前は、含まれる名前空間内で一意である必要があります。

名前空間は暗黙的に public され、名前空間の宣言にアクセス修飾子を含めることはできません。

namespace_body内では、省略可能なusing_directiveは他の名前空間、型、メンバーの名前をインポートし、修飾名ではなく直接参照できるようにします。 省略可能な namespace_member_declarationは、名前空間の宣言空間にメンバーを提供します。 すべての using_directiveは、メンバー宣言の前に表示されることに注意してください。

namespace_declarationqualified_identifierは、単一の識別子または "." トークンで区切られた一連の識別子です。 後者の形式では、プログラムは、複数の名前空間宣言を字句的に入れ子にすることなく、入れ子になった名前空間を定義できます。

例:

namespace N1.N2
{
    class A {}
    class B {}
}

はセマンティックに同等です。

namespace N1
{
    namespace N2
    {
        class A {}
        class B {}
    }
}

end の例

名前空間はオープン エンドであり、同じ完全修飾名 (§7.8.2) を持つ 2 つの名前空間宣言は、同じ宣言空間 (§7.3) に影響します。

: 次のコード内

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

上記の 2 つの名前空間宣言は同じ宣言空間に影響します。この場合、完全修飾名を持つ 2 つのクラスを N1.N2.A および N1.N2.B宣言します。 2 つの宣言は同じ宣言空間に影響するため、それぞれが同じ名前のメンバーの宣言を含む場合はエラーでした。

end の例

14.4 Extern エイリアス ディレクティブ

extern_alias_directiveでは、名前空間のエイリアスとして機能する識別子が導入されます。 エイリアス化された名前空間の仕様は、プログラムのソース コードの外部にあり、エイリアス化された名前空間の入れ子になった名前空間にも適用されます。

extern_alias_directive
    : 'extern' 'alias' identifier ';'
    ;

extern_alias_directiveのスコープは、すぐにcompilation_unitまたはnamespace_bodyを含むusing_directiveglobal_attributes、およびnamespace_member_declarationにわたって拡張されます。

extern_alias_directiveを含むコンパイル ユニットまたは名前空間本体内で、extern_alias_directiveによって導入された識別子を使用して、エイリアス化された名前空間を参照できます。 identifierglobal という単語になるというコンパイル時エラーです。

extern_alias_directiveによって導入されるエイリアスは、using_alias_directiveによって導入されたエイリアスによく似ています。 extern_alias_directiveusing_alias_directiveの詳細については、§14.5.2 を参照してください。

aliasはコンテキスト キーワード (§6.4.4) であり、extern_alias_directive内の extern キーワードの直後にある場合にのみ特別な意味を持ちます。

外部定義が指定されていない extern エイリアスをプログラムが宣言すると、エラーが発生します。

: 次のプログラムは、2 つの extern エイリアス ( XY) を宣言して使用します。これらはそれぞれ個別の名前空間階層のルートを表します。

extern alias X;
extern alias Y;

class Test
{
    X::N.A a;
    X::N.B b1;
    Y::N.B b2;
    Y::N.C c;
}

プログラムは、 X および Yの extern エイリアスの存在を宣言しますが、エイリアスの実際の定義はプログラムの外部にあります。 同じ名前の N.B クラスを X.N.B および Y.N.Bとして参照したり、名前空間エイリアス修飾子、 X::N.BY::N.Bを使用したりできるようになりました。 end の例

14.5 ディレクティブの使用

14.5.1 全般

ディレクティブを使用すると 他の名前空間で定義されている名前空間と型の使用が容易になります。 ディレクティブを使用すると、 namespace_or_type_name (§7.8) と simple_name (§12.8.4) の名前解決プロセスに影響しますが、宣言とは異なり、 using_directiveは、使用されるコンパイル ユニットまたは名前空間の基になる宣言スペースに新しいメンバーを提供しません。

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

using_alias_directive (§14.5.2) には、名前空間または型のエイリアスが導入されています。

using_namespace_directive (§14.5.3) は、名前空間の型メンバーをインポートします。

using_static_directive (§14.5.4) は、入れ子になった型と型の静的メンバーをインポートします。

using_directiveのスコープは、すぐに含まれるコンパイルユニットまたは名前空間本体のnamespace_member_declarationsに拡張されます。 using_directiveのスコープには、そのピア using_directiveは特に含まれません。 したがって、ピア using_directiveは互いに影響を与えるのではなく、書き込まれる順序は重要ではありません。 これに対し、 extern_alias_directive のスコープには、同じコンパイル 単位または名前空間本体で定義された using_directiveが含まれます。

14.5.2 エイリアス ディレクティブの使用

using_alias_directiveは、すぐに囲むコンパイル 単位または名前空間本体内の名前空間または型のエイリアスとして機能する識別子を導入します。

using_alias_directive
    : 'using' identifier '=' namespace_or_type_name ';'
    ;

using_alias_directiveを含むコンパイル ユニットまたは名前空間本体のグローバル属性とメンバー宣言内では、using_alias_directiveによって導入された識別子を使用して、指定された名前空間または型を参照できます。

例:

namespace N1.N2
{
    class A {}
}
namespace N3
{
    using A = N1.N2.A;

    class B: A {}
}

上記では、 N3 名前空間のメンバー宣言内では、 AN1.N2.Aのエイリアスであるため、クラス N3.B はクラス N1.N2.Aから派生します。 N1.N2のエイリアス Rを作成し、R.Aを参照することで、同じ効果を得ることができます。

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

end の例

extern_alias_directiveを含むコンパイル 単位または名前空間本体でディレクティブ、グローバル属性、メンバー宣言を使用する中で、extern_alias_directiveによって導入された識別子を使用して、関連付けられた名前空間を参照できます。

: 次に例を示します。

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

上記では、 N1 名前空間のメンバー宣言内では、 N2 は、プログラムのソース コードの外部にある定義を持つ名前空間のエイリアスです。 クラス N1.B は、クラス N2.Aから派生します。 N2.Aのエイリアス Aを作成し、Aを参照することで、同じ効果を得ることができます。

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

end の例

extern_alias_directiveまたはusing_alias_directiveでは、特定のコンパイル ユニットまたは名前空間本体内でエイリアスを使用できますが、基になる宣言空間に新しいメンバーは提供されません。 言い換えると、エイリアス ディレクティブは推移的ではなく、発生するコンパイル単位または名前空間本体にのみ影響します。

: 次のコード内

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

namespace N3
{
    class B : R1::A, R2.I {} // Error, R1 and R2 unknown
}

R1R2を導入するエイリアス ディレクティブのスコープは、それが含まれている名前空間本体のメンバー宣言にのみ拡張されるため、2 番目の名前空間宣言ではR1R2は不明です。 ただし、エイリアス ディレクティブを含むコンパイル 単位に配置すると、両方の名前空間宣言内でエイリアスが使用できるようになります。

extern alias R1;

using R2 = N1.N2;

namespace N3
{
    class B : R1::A, R2.I {}
}

namespace N3
{
    class C : R1::A, R2.I {}
}

end の例

compilation_unitまたはnamespace_body内の各extern_alias_directiveまたはusing_alias_directiveは、すぐに囲むcompilation_unitまたはnamespace_bodyのエイリアス宣言空間 (§7.3) に名前を付けます。 エイリアス ディレクティブの identifier は、対応するエイリアス宣言空間内で一意である必要があります。 エイリアス識別子は、グローバル宣言空間内または対応する名前空間の宣言空間内で一意である必要はありません。

例:

extern alias X;
extern alias Y;

using X = N1.N2; // Error: alias X already exists

class Y {} // Ok

Xという名前のエイリアスを使用すると、同じコンパイル ユニットに X という名前のエイリアスが既に存在するため、エラーが発生します。 Yという名前のクラスは、Yという名前の extern エイリアスと競合しません。これらの名前は個別の宣言スペースに追加されるためです。 前者はグローバル宣言空間に追加され、後者はこのコンパイルユニットのエイリアス宣言スペースに追加されます。

エイリアス名が名前空間のメンバーの名前と一致する場合は、いずれかを適切に修飾する必要があります。

namespace N1.N2
{
    class B {}
}

namespace N3
{
    class A {}
    class B : A {}
}

namespace N3
{
    using A = N1.N2;
    using B = N1.N2.B;

    class W : B {} // Error: B is ambiguous
    class X : A.B {} // Error: A is ambiguous
    class Y : A::B {} // Ok: uses N1.N2.B
    class Z : N3.B {} // Ok: uses N3.B
}

N3の 2 番目の名前空間本体では、Bを修飾しないとエラーが発生します。N3には、Bという名前のメンバーと、名前Bを持つエイリアスも宣言する名前空間本体が含まれるため、Aの場合と同様です。 クラス N3.B は、 N3.B または global::N3.Bとして参照できます。 エイリアス A は、 修飾された alias-member (§14.8) ( A::B など) で使用できます。 エイリアス B は基本的に役に立ちません。 qualified_alias_memberでは名前空間エイリアスのみを使用でき、型のエイリアスをBするため、qualified_alias_memberでは使用できません。

end の例

通常のメンバーと同様に、 alias_directives によって導入された名前は、入れ子になったスコープ内の同様の名前のメンバーによって非表示になります。

: 次のコード内

using R = N1.N2;

namespace N3
{
    class R {}
    class B: R.A {} // Error, R has no member A
}

RN1.N2ではなくN3.Rを参照するため、B宣言のR.Aへの参照によってコンパイル時エラーが発生します。

end の例

extern_alias_directiveが記述される順序には意味がありません。 同様に、 using_alias_directiveが書き込まれる順序には意味はありませんが、すべての using_alias_directives は、同じコンパイル単位または名前空間本体のすべての extern_alias_directiveの後に来る必要があります。 using_alias_directiveによって参照されるnamespace_or_type_nameの解決は、using_alias_directive自体や、すぐに含むコンパイルユニットまたは名前空間本体の他のusing_directiveの影響を受けませんが、すぐに含むコンパイルユニットまたは名前空間本体のextern_alias_directiveによって影響を受ける可能性があります。 つまり、using_alias_directivenamespace_or_type_nameは、すぐに含まれるコンパイルユニットまたは名前空間本体にusing_directiveがなく、適切なextern_alias_directiveセットがあるかのように解決されます。

: 次のコード内

namespace N1.N2 {}

namespace N3
{
    extern alias X;

    using R1 = X::N; // OK
    using R2 = N1; // OK
    using R3 = N1.N2; // OK
    using R4 = R2.N2; // Error, R2 unknown
}

最後の using_alias_directive では、前の using_alias_directiveの影響を受けないため、コンパイル時エラーが発生します。 extern エイリアス X のスコープにはusing_alias_directiveが含まれるため、最初のusing_alias_directiveではエラーは発生しません。

end の例

using_alias_directiveは、名前空間または型のエイリアスを作成できます。これには、名前空間が表示される名前空間や、その名前空間内に入れ子になった型が含まれます。

エイリアスを使用して名前空間または型にアクセスすると、宣言された名前を使用してその名前空間または型にアクセスするのとまったく同じ結果が得られます。

: Given

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using R1 = N1;
    using R2 = N1.N2;

    class B
    {
        N1.N2.A a; // refers to N1.N2.A
        R1.N2.A b; // refers to N1.N2.A
        R2.A c; // refers to N1.N2.A
    }
}

N1.N2.AR1.N2.A、およびR2.Aの名前は同等であり、すべて完全修飾名がN1.N2.Aクラス宣言を参照します。

end の例

部分型 (§15.2.7) の各部分は同じ名前空間内で宣言されますが、通常、部分は異なる名前空間宣言内で記述されます。 したがって、パーツごとに異なる extern_alias_directiveusing_directiveを存在させることができます。 1 つの部分内で単純な名前 (§12.8.4) を解釈する場合は、名前空間本体の extern_alias_directiveusing_directiveと、その部分を囲むコンパイル単位のみが考慮されます。 これにより、同じ識別子が異なる部分で異なる意味を持つ可能性があります。

例:

namespace N
{
    using List = System.Collections.ArrayList;

    partial class A
    {
        List x; // x has type System.Collections.ArrayList
    }
}

namespace N
{
    using List = Widgets.LinkedList;

    partial class A
    {
        List y; // y has type Widgets.LinkedList
    }
}

end の例

エイリアスを使用すると、閉じた構築された型に名前を付けることができますが、型引数を指定しないと、バインドされていないジェネリック型宣言に名前を付けることはできません。

例:

namespace N1
{
    class A<T>
    {
        class B {}
    }
}

namespace N2
{
    using W = N1.A;       // Error, cannot name unbound generic type
    using X = N1.A.B;     // Error, cannot name unbound generic type
    using Y = N1.A<int>;  // Ok, can name closed constructed type
    using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters
}

end の例

14.5.3 名前空間ディレクティブの使用

using_namespace_directiveは、名前空間に含まれる型をすぐに囲むコンパイルユニットまたは名前空間本体にインポートし、修飾なしで各型の識別子を使用できるようにします。

using_namespace_directive
    : 'using' namespace_name ';'
    ;

using_namespace_directiveを含むコンパイル 単位または名前空間本体のメンバー宣言内で、指定された名前空間に含まれる型を直接参照できます。

例:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

上記では、 N3 名前空間のメンバー宣言内で、 N1.N2 の型メンバーを直接使用できるため、クラス N3.B はクラス N1.N2.Aから派生します。

end の例

using_namespace_directiveは、特定の名前空間に含まれる型をインポートしますが、具体的には入れ子になった名前空間はインポートしません。

: 次のコード内

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1;
    class B : N2.A {} // Error, N2 unknown
}

using_namespace_directiveN1に含まれる型をインポートしますが、N1に入れ子になった名前空間はインポートしません。 したがって、B宣言でN2.Aを参照すると、スコープ内に N2 という名前のメンバーがないため、コンパイル時エラーが発生します。

end の例

using_alias_directiveとは異なり、using_namespace_directiveは、外側のコンパイルユニットまたは名前空間本体内で識別子が既に定義されている型をインポートできます。 実際には、 using_namespace_directive によってインポートされた名前は、外側のコンパイル ユニットまたは名前空間本体内の同様の名前付きメンバーによって非表示になります。

例:

namespace N1.N2
{
    class A {}
    class B {}
}

namespace N3
{
    using N1.N2;
    class A {}
}

ここでは、N3名前空間のメンバー宣言内で、AN1.N2.AではなくN3.Aを参照します。

end の例

複数のインポートされた名前空間で同じ型名が導入されている場合、名前があいまいになる可能性があるため、 using_alias_directive は参照を明確にするのに役立ちます。

: 次のコード内

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

    class B : A {} // Error, A is ambiguous
}

N1N2の両方にメンバー Aが含まれています。また、N3が両方をインポートするため、N3Aを参照することはコンパイル時エラーです。 このような状況では、競合を解決するには、Aへの参照の修飾を使用するか、特定のAを選択するusing_alias_directiveを導入します。 次に例を示します。

namespace N3
{
    using N1;
    using N2;
    using A = N1.A;

    class B : A {} // A means N1.A
}

end の例

さらに、同じコンパイル 単位または名前空間本体の using_namespace_directiveまたは using_static_directiveによってインポートされた複数の名前空間または型に同じ名前の型またはメンバーが含まれている場合、その名前への参照は simple_name としてあいまいと見なされます。

例:

namespace N1
{
    class A {}
}

class C
{
    public static int A;
}

namespace N2
{
    using N1;
    using static C;

    class B
    {
        void M()
        {
            A a = new A();   // Ok, A is unambiguous as a type-name
            A.Equals(2);     // Error, A is ambiguous as a simple-name
        }
    }
}

N1 には型メンバー Aが含まれており、 C には静的フィールド Aが含まれています。また、 N2 が両方をインポートするため、 Asimple_name として参照することはあいまいであり、コンパイル時エラーです。

end の例

using_alias_directiveと同様に、using_namespace_directiveは、コンパイル ユニットまたは名前空間の基になる宣言空間に新しいメンバーを提供するのではなく、表示されるコンパイル単位または名前空間本体にのみ影響します。

using_namespace_directiveによって参照されるnamespace_nameは、using_alias_directiveによって参照されるnamespace_or_type_nameと同じ方法で解決されます。 したがって、同じコンパイル単位または名前空間本体内の using_namespace_directiveは互いに影響を与えるのではなく、任意の順序で書き込むことができます。

14.5.4 静的ディレクティブの使用

using_static_directiveは、型宣言に直接含まれる入れ子になった型と静的メンバーを、すぐに囲むコンパイル単位または名前空間本体にインポートし、各メンバーと型の識別子を修飾なしで使用できるようにします。

using_static_directive
    : 'using' 'static' type_name ';'
    ;

using_static_directiveを含むコンパイル ユニットまたは名前空間本体のメンバー宣言内では、指定された型の宣言に直接含まれる、アクセス可能な入れ子になった型と静的メンバー (拡張メソッドを除く) を直接参照できます。

例:

namespace N1
{
   class A 
   {
        public class B {}
        public static B M() => new B();
   }
}

namespace N2
{
    using static N1.A;

    class C
    {
        void N()
        {
            B b = M();
        }
    }
}

前のコードでは、N2名前空間のメンバー宣言内で、静的メンバーと入れ子になった型のN1.Aを直接使用できるため、メソッドNN1.ABメンバーとMメンバーの両方を参照できます。

end の例

using_static_directiveでは、拡張メソッドを静的メソッドとして直接インポートするのではなく、拡張メソッドの呼び出しに使用できるようにします (§12.8.9.3)。

例:

namespace N1 
{
    static class A 
    {
        public static void M(this string s){}
    }
}

namespace N2
{
    using static N1.A;

    class B
    {
        void N()
        {
            M("A");      // Error, M unknown
            "B".M();     // Ok, M known as extension method
            N1.A.M("C"); // Ok, fully qualified
        }
    }
}

using_static_directiveは、N1.Aに含まれる拡張メソッドMをインポートしますが、拡張メソッドとしてのみインポートします。 したがって、B.N本体内のMへの最初の参照では、スコープ内に M という名前のメンバーがないため、コンパイル時エラーが発生します。

end の例

using_static_directiveは、基底クラスで宣言されたメンバーと型ではなく、指定された型で直接宣言されたメンバーと型のみをインポートします。

例:

namespace N1 
{
    class A 
    {
        public static void M(string s){}
    }

    class B : A
    {
        public static void M2(string s){}
    }
}

namespace N2
{
    using static N1.B;

    class C
    {
        void N()
        {
            M2("B");      // OK, calls B.M2
            M("C");       // Error. M unknown 
        }
    }
}

using_static_directiveは、N1.Bに含まれるメソッドM2をインポートしますが、N1.Aに含まれるメソッドMインポートしません。 したがって、C.N本体のMへの参照では、スコープ内に M という名前のメンバーがないため、コンパイル時エラーが発生します。 開発者は、N1.A内のメソッドもインポートする必要があることを指定するために、2 つ目のusing static ディレクティブを追加する必要があります。

end の例

複数の using_namespace_directivesusing_static_directives のあいまいさは、 §14.5.3 で説明されています。

14.6 名前空間メンバー宣言

namespace_member_declarationは、namespace_declaration (§14.3) またはtype_declaration (§14.7) のいずれかです。

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

コンパイル ユニットまたは名前空間本体には namespace_member_declarationを含めることができます。このような宣言は、含まれているコンパイル ユニットまたは名前空間本体の基になる宣言空間に新しいメンバーを提供します。

14.7 型宣言

type_declarationは、class_declaration (§15.2)、struct_declaration (§16.2)、interface_declaration () です。 §18.2)、enum_declaration (§19.2)、またはdelegate_declaration (§20.2)。

type_declaration
    : class_declaration
    | struct_declaration
    | interface_declaration
    | enum_declaration
    | delegate_declaration
    ;

type_declarationは、コンパイル ユニットの最上位宣言として、または名前空間、クラス、または構造体内のメンバー宣言として発生する可能性があります。

T の型宣言がコンパイル単位で最上位レベルの宣言として発生する場合、型宣言の完全修飾名 (§7.8.2) は宣言の非修飾名 (§7.8.2) と同じです。 型 T の型宣言が名前空間、クラス、または構造体宣言内で発生する場合、型宣言の完全修飾名 (§7.8.3) が S.Nされます。ここで、 S は、含まれる名前空間、クラス、または構造体宣言の完全修飾名であり、 N は宣言の非修飾名です。

クラスまたは構造体内で宣言された型は、入れ子になった型 (§15.3.9) と呼ばれます。

許可されるアクセス修飾子と型宣言の既定のアクセスは、宣言が行われるコンテキストによって異なります (§7.5.2)。

  • コンパイル 単位または名前空間で宣言された型は、 public または internal アクセスできます。 既定値は internal アクセスです。
  • クラスで宣言された型は、 publicprotected internalprotectedprivate protectedinternal、または private アクセスを持つことができます。 既定値は private アクセスです。
  • 構造体で宣言された型は、 publicinternal、または private アクセスを持つことができます。 既定値は private アクセスです。

14.8 修飾されたエイリアス メンバー

14.8.1 全般

namespace エイリアス修飾子 ::を使用すると、新しい型とメンバーの導入によって型名の参照が影響を受けないことを保証できます。 名前空間エイリアス修飾子は常に、左側の識別子と右側の識別子と呼ばれる 2 つの識別子の間に表示されます。 通常の . 修飾子とは異なり、 :: 修飾子の左側の識別子は、extern または using エイリアスとしてのみ検索されます。

qualified_alias_memberは、グローバル名前空間への明示的なアクセスと、他のエンティティによって隠される可能性があるエイリアスの使用を明示的に提供します。

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

qualified_alias_memberは、namespace_or_type_name (§7.8) またはmember_accessの左オペランド (§12.8.7) として使用できます。

qualified_alias_memberは、左側の識別子と右側の識別子と呼ばれる 2 つの識別子で構成され、:: トークンで区切られ、必要に応じてtype_argument_listが続きます。 左側の識別子がグローバルである場合、グローバル名前空間は右側の識別子を検索します。 その他の左側の識別子の場合、その識別子は extern またはエイリアス (§14.4 および §14.5.2) として検索されます。 このようなエイリアスがない場合、またはエイリアスが型を参照している場合、コンパイル時エラーが発生します。 エイリアスが名前空間を参照している場合、その名前空間は右側の識別子を検索します。

qualified_alias_memberには、次の 2 つの形式があります。

  • N::I<A₁, ..., Aₑ>では、 NI は識別子を表し、 <A₁, ..., Aₑ> は型引数リストです。 (e は常に少なくとも 1 つです。
  • N::I: NI は識別子を表します。 (この場合、 e は 0 と見なされます)。

この表記を使用して、 qualified_alias_member の意味は次のように決定されます。

  • Nが識別子globalの場合、グローバル名前空間はIを検索します。
    • グローバル名前空間に I という名前の名前空間が含まれており、 e が 0 の場合、 qualified_alias_member はその名前空間を参照します。
    • それ以外の場合、グローバル名前空間に I という名前の非ジェネリック型が含まれており、 e が 0 の場合、 qualified_alias_member はその型を参照します。
    • それ以外の場合、グローバル名前空間にe型パラメーターを持つ I という名前の型が含まれている場合、qualified_alias_memberは、指定された型引数で構築されたその型を参照します。
    • それ以外の場合、 qualified_alias_member は未定義であり、コンパイル時エラーが発生します。
  • それ以外の場合は、すぐにqualified_alias_memberを格納する名前空間宣言 (§14.3) から始まり、外側の各名前空間宣言 (存在する場合) を続行し、qualified_alias_memberを含むコンパイル単位で終わると、エンティティが見つかるまで次の手順が評価されます。
    • 名前空間宣言またはコンパイル ユニットに N を型に関連付ける using_alias_directive が含まれている場合、 qualified_alias_member は未定義であり、コンパイル時エラーが発生します。
    • それ以外の場合、名前空間の宣言またはコンパイル単位に、Nを名前空間に関連付けるextern_alias_directiveまたはusing_alias_directiveが含まれている場合は、次のようになります。
      • Nに関連付けられている名前空間に I という名前の名前空間が含まれており、eが 0 の場合、qualified_alias_memberはその名前空間を参照します。
      • それ以外の場合、 N に関連付けられている名前空間に I という名前の非ジェネリック型が含まれており、 e が 0 の場合、 qualified_alias_member はその型を参照します。
      • それ以外の場合、Nに関連付けられている名前空間に、e型パラメーターを持つ I という名前の型が含まれている場合、qualified_alias_memberは、指定された型引数で構築されたその型を参照します。
      • それ以外の場合、 qualified_alias_member は未定義であり、コンパイル時エラーが発生します。
  • それ以外の場合、 qualified_alias_member は未定義であり、コンパイル時エラーが発生します。

: コード内:

using S = System.Net.Sockets;

class A
{
    public static int x;
}

class C
{
    public void F(int A, object S)
    {
        // Use global::A.x instead of A.x
        global::A.x += A;
        // Use S::Socket instead of S.Socket
        S::Socket s = S as S::Socket;
    }
}

クラス Aglobal::A で参照され、 System.Net.Sockets.Socket 型は S::Socketで参照されます。 代わりに A.xS.Socket を使用すると、 AS がパラメーターに解決されるため、コンパイル時エラーが発生する可能性があります。

end の例

: global 識別子は、 qualified_alias_nameの左側の識別子として使用される場合にのみ特別な意味を持ちます。 キーワードではなく、それ自体がエイリアスではありません。コンテキスト キーワードです (§6.4.4)。 コードで次の手順を実行します。

class A { }

class C
{
    global.A x; // Error: global is not defined
    global::A y; // Valid: References A in the global namespace
}

global.Aを使用すると、スコープにglobalという名前のエンティティがないため、コンパイル時エラーが発生します。 global という名前のエンティティがスコープ内にある場合、global.A内のglobalはそのエンティティに解決されます。

qualified_alias_memberの左側の識別子としてglobalを使用すると、globalという名前の using エイリアスがある場合でも、常にglobal名前空間で参照が発生します。 コードで次の手順を実行します。

using global = MyGlobalTypes;

class A { }

class C 
{
    global.A x; // Valid: References MyGlobalTypes.A
    global::A y; // Valid: References A in the global namespace
}

global.AMyGlobalTypes.A に解決され、 global::A はグローバル名前空間のクラス A に解決されます。

end note

14.8.2 エイリアスの一意性

各コンパイル ユニットと名前空間本体には、extern エイリアスとエイリアスを使用するための個別の宣言空間があります。 したがって、extern エイリアスまたは using エイリアスの名前は、extern エイリアスのセット内で一意であり、すぐに含まれるコンパイルユニットまたは名前空間本体で宣言されたエイリアスを使用する必要があります。エイリアスは、 :: 修飾子でのみ使用される限り、型または名前空間と同じ名前を持つことができます。

: 次の例を参照してください。

namespace N
{
    public class A {}
    public class B {}
}

namespace N
{
    using A = System.IO;

    class X
    {
        A.Stream s1; // Error, A is ambiguous
        A::Stream s2; // Ok
    }
}

クラス Aと using エイリアス Aの両方がスコープ内にあるため、名前Aには 2 つの意味があります。 このため、修飾名A.StreamAを使用するとあいまいになり、コンパイル時エラーが発生します。 ただし、Aは名前空間エイリアスとしてのみ検索されるため、::修飾子でAを使用してもエラーになりません。

end の例