次の方法で共有


14 名前空間

14.1 全般

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

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

14.2 コンパイル単位

compilation_unitは、0 個以上のextern_alias_directiveから成、その後に 0 個以上のusing_directives が続き、その後に 0 個以上のglobal_attributesが続きその後に 0 個以上のnamespace_member_declarations が続きます。 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 つの宣言空間にメンバーを提供します。

Example:

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

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

終了サンプル

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

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

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

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

Example:

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

は、次と同じ意味です:

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

終了サンプル

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

: 次のコード内

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

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

終了サンプル

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によって導入された識別子を使用して、エイリアス化された名前空間を参照できます。 識別子global という単語になるというコンパイル時エラーです。

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

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

外部定義が指定されていない 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を使用したりできるようになりました。 終了サンプル

14.5 ディレクティブの使用

14.5.1 全般

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

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 エイリアス ディレクティブ

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

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

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

Example:

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

    class B: A {}
}

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

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

終了サンプル

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

: 次に例を示します。

namespace N1
{
    extern alias N2;

    class B : N2::A {}
}

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

namespace N1
{
    extern alias N2;

    using A = N2::A;

    class B : A {}
}

終了サンプル

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 {}
}

終了サンプル

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

Example:

extern alias X;
extern alias Y;

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

class Y {} // Ok

X という名前の using エイリアスでは、同じコンパイル単位に 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は、A::Bなどの修飾されたエイリアス メンバー (§14.8) で使用できます。 エイリアス B は基本的に役に立ちません。 qualified_alias_memberでは名前空間エイリアスのみを使用でき、のエイリアスをBするため、qualified_alias_memberでは使用できません。

終了サンプル

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

: 次のコード内

using R = N1.N2;

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

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

終了サンプル

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ではエラーは発生しません。

終了サンプル

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 クラス宣言を参照します。

終了サンプル

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

Example:

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
    }
}

終了サンプル

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

Example:

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
}

終了サンプル

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

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

using_namespace_directive
    : 'using' namespace_name ';'
    ;

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

Example:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

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

終了サンプル

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

: 次のコード内

namespace N1.N2
{
    class A {}
}

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

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

終了サンプル

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

Example:

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

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

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

終了サンプル

複数のインポートされた名前空間で同じ型名が導入されている場合、名前があいまいになる可能性があるため、 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 が両方をインポートするため、AN3 を参照することはコンパイル時エラーとなります。 このような状況では、競合を解決するには、Aへの参照の修飾を使用するか、特定のAを選択するusing_alias_directiveを導入します。 例えば次が挙げられます。

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

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

終了サンプル

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

Example:

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が両方をインポートするため、simple_nameとしてAを参照することはあいまいであり、コンパイル時エラーです。

終了サンプル

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

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

14.5.4 static ディレクティブの使用

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

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

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

Example:

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 を直接使用できるため、メソッド NBM メンバーと N1.A メンバーの両方を参照できます。

終了サンプル

using_static_directiveでは、拡張メソッドは静的メソッドとして直接インポートされませんが、拡張メソッドの呼び出し (§12.8.10.3) で使用できます。

Example:

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をインポートしますが、拡張メソッドとしてのみインポートします。 したがって、M の本体で B.N を最初に参照すると、スコープ内に M という名前のメンバーがないため、コンパイル時エラーが発生します。

終了サンプル

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

Example:

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

終了サンプル

§14.5.3 では複数のusing_namespace_directivesとusing_static_directivesの間のあいまいさが説明されています。

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.3) は宣言の非修飾名 (§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 は未定義であり、コンパイル時エラーが発生します。
  • それ以外の場合は、名前空間宣言 (§14.3) からすぐに qualified_alias_member (存在する場合) を含み、外側の名前空間宣言 (存在する場合) を続け、 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 がパラメーターに解決されるため、コンパイル時エラーが発生する可能性があります。

終了サンプル

: 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 内の global.A はそのエンティティに解決されます。

globalqualified_alias_memberの左側の識別子として使用すると、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 に解決されます。

注釈

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 つの意味があります。 このため、修飾名 AA.Stream を使用するとあいまいになり、コンパイル時エラーが発生します。 ただし、A は名前空間エイリアスとしてのみ検索されるため、::修飾子で A を使用してもエラーになりません。

終了サンプル