Поделиться через


14 Namespaces

14.1 General

Программы C# упорядочены с помощью пространств имен. Пространства имен используются как в качестве внутренней системы организации для программы, так и как внешняя система организации — способ представления элементов программы, предоставляемых другим программам.

Using directives (§14.5) are provided to facilitate the use of namespaces.

Единицы компиляции 14.2

A compilation_unit consists of zero or more extern_alias_directives followed by zero or more using_directives followed by zero or one global_attributes followed by zero or more namespace_member_declarations. The compilation_unit defines the overall structure of the input.

compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;

Программа C# состоит из одного или нескольких единиц компиляции. При компиляции программы C# все единицы компиляции обрабатываются вместе. Таким образом, единицы компиляции могут зависеть друг от друга, возможно, в циклической форме.

The extern_alias_directives of a compilation unit affect the using_directives, global_attributes and namespace_member_declarations of that compilation unit, but have no effect on other compilation units.

The using_directives of a compilation unit affect the global_attributes and namespace_member_declarations of that compilation unit, but have no effect on other compilation units.

The global_attributes (§22.3) of a compilation unit permit the specification of attributes for the target assembly and module. Сборки и модули служат физическими контейнерами для типов. Сборка может состоять из нескольких физически отдельных модулей.

The namespace_member_declarations of each compilation unit of a program contribute members to a single declaration space called the global namespace.

Example:

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

Два единицы компиляции способствуют одному глобальному пространству имен, в этом случае объявляя два класса с полными именами A и B. Так как два единици компиляции способствуют одному и тому же пространству объявлений, это было бы ошибкой, если каждая из них содержала объявление члена с одинаковым именем.

end example

Объявления пространства имен 14.3

A namespace_declaration consists of the keyword namespace, followed by a namespace name and body, optionally followed by a semicolon.

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

qualified_identifier
    : identifier ('.' identifier)*
    ;

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

A namespace_declaration may occur as a top-level declaration in a compilation_unit or as a member declaration within another namespace_declaration. When a namespace_declaration occurs as a top-level declaration in a compilation_unit, the namespace becomes a member of the global namespace. When a namespace_declaration occurs within another namespace_declaration, the inner namespace becomes a member of the outer namespace. В любом случае имя пространства имен должно быть уникальным в пределах содержащего пространства имен.

Пространства имен неявно public и объявление пространства имен не может включать модификаторы доступа.

Within a namespace_body, the optional using_directives import the names of other namespaces, types and members, allowing them to be referenced directly instead of through qualified names. The optional namespace_member_declarations contribute members to the declaration space of the namespace. Note that all using_directives shall appear before any member declarations.

The qualified_identifier of a namespace_declaration may be a single identifier or a sequence of identifiers separated by “.” tokens. Последняя форма позволяет программе определять вложенное пространство имен без лексического вложения нескольких объявлений пространства имен.

Example:

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

семантически эквивалентен

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

end example

Namespaces are open-ended, and two namespace declarations with the same fully qualified name (§7.8.3) contribute to the same declaration space (§7.3).

Example: In the following code

namespace N1.N2
{
    class A {}
}

namespace N1.N2
{
    class B {}
}

Два объявления пространства имен, приведенные выше, способствуют одному и тому же пространству объявлений, в этом случае объявляя два класса с полными именами N1.N2.A и N1.N2.B. Так как два объявления способствуют одному и тому же пространству объявлений, это было бы ошибкой, если каждая из них содержала объявление члена с одинаковым именем.

end example

Директивы псевдонима Extern 14.4

An extern_alias_directive introduces an identifier that serves as an alias for a namespace. Спецификация псевдонима пространства имен является внешней к исходному коду программы и применяется также к вложенным пространствам имен псевдонима пространства имен.

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

The scope of an extern_alias_directive extends over the using_directives, global_attributes and namespace_member_declarations of its immediately containing compilation_unit or namespace_body.

Within a compilation unit or namespace body that contains an extern_alias_directive, the identifier introduced by the extern_alias_directive can be used to reference the aliased namespace. It is a compile-time error for the identifier to be the word global.

The alias introduced by an extern_alias_directive is very similar to the alias introduced by a using_alias_directive. See §14.5.2 for more detailed discussion of extern_alias_directives and using_alias_directives.

alias is a contextual keyword (§6.4.4) and only has special meaning when it immediately follows the extern keyword in an extern_alias_directive.

Ошибка возникает, если программа объявляет экстерн-псевдоним, для которого отсутствует внешнее определение.

Example: The following program declares and uses two extern aliases, X and Y, each of which represent the root of a distinct namespace hierarchy:

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, однако фактические определения псевдонимов являются внешними для программы. Теперь классы с одинаковыми именами N.B можно ссылаться как X.N.B и (или Y.N.B) с помощью квалификатора X::N.B пространства имен и Y::N.B. end example

Директивы using 14.5

14.5.1 General

Using directives facilitate the use of namespaces and types defined in other namespaces. Using directives impact the name resolution process of namespace_or_type_names (§7.8) and simple_names (§12.8.4), but unlike declarations, using_directives do not contribute new members to the underlying declaration spaces of the compilation units or namespaces within which they are used.

using_directive
    : using_alias_directive
    | using_namespace_directive
    | using_static_directive    
    ;

A using_alias_directive (§14.5.2) introduces an alias for a namespace or type.

A using_namespace_directive (§14.5.3) imports the type members of a namespace.

A using_static_directive (§14.5.4) imports the nested types and static members of a type.

The scope of a using_directive extends over the namespace_member_declarations of its immediately containing compilation unit or namespace body. The scope of a using_directive specifically does not include its peer using_directives. Thus, peer using_directives do not affect each other, and the order in which they are written is insignificant. In contrast, the scope of an extern_alias_directive includes the using_directives defined in the same compilation unit or namespace body.

14.5.2 Использование директив псевдонима

A using_alias_directive introduces an identifier that serves as an alias for a namespace or type within the immediately enclosing compilation unit or namespace body.

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

Within global attributes and member declarations in a compilation unit or namespace body that contains a using_alias_directive, the identifier introduced by the using_alias_directive can be used to reference the given namespace or type.

Example:

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

    class B: A {}
}

Выше в объявлениях членов в N3 пространстве имен используется псевдоним, Aпоэтому класс N1.N2.A является производным от классаN3.BN1.N2.A. Тот же эффект можно получить путем создания псевдонима R для N1.N2 и последующего R.Aссылки:

namespace N3
{
    using R = N1.N2;

    class B : R.A {}
}

end example

Within using directives, global attributes and member declarations in a compilation unit or namespace body that contains an extern_alias_directive, the identifier introduced by the extern_alias_directive can be used to reference the associated namespace.

Example: For example:

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

end example

An extern_alias_directive or using_alias_directive makes an alias available within a particular compilation unit or namespace body, but it does not contribute any new members to the underlying declaration space. Другими словами, директива псевдонима не является транзитивной, но, скорее, влияет только на блок компиляции или тело пространства имен, в котором она происходит.

Example: In the following code

namespace N3
{
    extern alias R1;

    using R2 = N1.N2;
}

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

области директив псевдонима, которые вводят R1 и R2 расширяют только объявления членов в теле пространства имен, в котором они содержатся, поэтому R1 и R2 неизвестны во втором объявлении пространства имен. Однако размещение директив псевдонима в блоке компиляции приводит к тому, что псевдоним становится доступным в обоих объявлениях пространства имен:

extern alias R1;

using R2 = N1.N2;

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

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

end example

Each extern_alias_directive or using_alias_directive in a compilation_unit or namespace_body contributes a name to the alias declaration space (§7.3) of the immediately enclosing compilation_unit or namespace_body. The identifier of the alias directive shall be unique within the corresponding alias declaration space. Идентификатор псевдонима не должен быть уникальным в пределах глобального пространства объявлений или пространства объявления соответствующего пространства имен.

Example:

extern alias X;
extern alias Y;

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

class Y {} // Ok

Именованный псевдоним X используется, так как в той же единице компиляции уже есть псевдоним X . Именованный класс Y не конфликтует с псевдонимом extern, Y так как эти имена добавляются в отдельные пространства объявлений. Первый добавляется в глобальное пространство объявления, а последний добавляется в пространство объявлений псевдонима для этой единицы компиляции.

Если имя псевдонима совпадает с именем члена пространства имен, использование любого из этих имен должно быть соответствующим образом квалифицировано:

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пространства имен для неквалифицированного использования B результатов ошибки, так как N3 содержит элемент с именем B и тело пространства имен, которое также объявляет псевдоним с именемB; аналогично.A N3.B Класс можно ссылаться как N3.B или global::N3.B. The alias A can be used in a qualified-alias-member (§14.8), such as A::B. Псевдоним B по сути бесполезен. It cannot be used in a qualified_alias_member since only namespace aliases can be used in a qualified_alias_member and B aliases a type.

end example

Just like regular members, names introduced by alias_directives are hidden by similarly named members in nested scopes.

Example: In the following code

using R = N1.N2;

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

Ссылка на R.A объявление B вызывает ошибку во время компиляции, так как R ссылается на N3.Rнее.N1.N2

end example

The order in which extern_alias_directives are written has no significance. Likewise, the order in which using_alias_directives are written has no significance, but all using_alias_directives shall come after all extern_alias_directives in the same compilation unit or namespace body. Resolution of the namespace_or_type_name referenced by a using_alias_directive is not affected by the using_alias_directive itself or by other using_directives in the immediately containing compilation unit or namespace body, but may be affected by extern_alias_directives in the immediately containing compilation unit or namespace body. In other words, the namespace_or_type_name of a using_alias_directive is resolved as if the immediately containing compilation unit or namespace body had no using_directives but has the correct set of extern_alias_directives.

Example: In the following code

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
}

the last using_alias_directive results in a compile-time error because it is not affected by the previous using_alias_directive. The first using_alias_directive does not result in an error since the scope of the extern alias X includes the using_alias_directive.

end example

A using_alias_directive can create an alias for any namespace or type, including the namespace within which it appears and any namespace or type nested within that namespace.

Доступ к пространству имен или типу с помощью псевдонима дает точно тот же результат, что и доступ к пространству имен или типу через объявленное имя.

Example: 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.A, R1.N2.Aи эквивалентны и R2.A все ссылаются на объявление класса, полное имя которого .N1.N2.A

end example

Although each part of a partial type (§15.2.7) is declared within the same namespace, the parts are typically written within different namespace declarations. Thus, different extern_alias_directives and using_directives can be present for each part. When interpreting simple names (§12.8.4) within one part, only the extern_alias_directives and using_directives of the namespace bodies and compilation unit enclosing that part are considered. Это может привести к тому, что один и тот же идентификатор имеет разные значения в разных частях.

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

end example

Используя псевдонимы, можно назвать закрытый созданный тип, но не удается назвать объявление универсального типа без указания аргументов типа.

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
}

end example

14.5.3 С помощью директив пространства имен

A using_namespace_directive imports the types contained in a namespace into the immediately enclosing compilation unit or namespace body, enabling the identifier of each type to be used without qualification.

using_namespace_directive
    : 'using' namespace_name ';'
    ;

Within member declarations in a compilation unit or namespace body that contains a using_namespace_directive, the types contained in the given namespace can be referenced directly.

Example:

namespace N1.N2
{
    class A {}
}

namespace N3
{
    using N1.N2;

    class B : A {}
}

Выше в объявлениях членов в N3 пространстве имен члены N1.N2 члены являются доступными напрямую и таким образом класс N3.B является производным от класса N1.N2.A.

end example

A using_namespace_directive imports the types contained in the given namespace, but specifically does not import nested namespaces.

Example: In the following code

namespace N1.N2
{
    class A {}
}

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

the using_namespace_directive imports the types contained in N1, but not the namespaces nested in N1. Таким образом, ссылка на N2.A объявление приводит к ошибке во время компиляции B , так как именованные N2 элементы не находятся в области.

end example

Unlike a using_alias_directive, a using_namespace_directive may import types whose identifiers are already defined within the enclosing compilation unit or namespace body. In effect, names imported by a using_namespace_directive are hidden by similarly named members in the enclosing compilation unit or namespace body.

Example:

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

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

Здесь, в объявлениях членов в N3 пространстве имен, A ссылается N3.A на нее N1.N2.A.

end example

Because names may be ambiguous when more than one imported namespace introduces the same type name, a using_alias_directive is useful to disambiguate the reference.

Example: In the following code

namespace N1
{
    class A {}
}

namespace N2
{
    class A {}
}

namespace N3
{
    using N1;
    using N2;

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

N1 и N2 содержит элементA, и, поскольку N3 импортирует оба, ссылка A в N3 нее является ошибкой во время компиляции. In this situation, the conflict can be resolved either through qualification of references to A, or by introducing a using_alias_directive that picks a particular A. For example:

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

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

end example

Furthermore, when more than one namespace or type imported by using_namespace_directives or using_static_directives in the same compilation unit or namespace body contain types or members by the same name, references to that name as a simple_name are considered ambiguous.

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 contains a type member A, and C contains a static field A, and because N2 imports both, referencing A as a simple_name is ambiguous and a compile-time error.

end example

Like a using_alias_directive, a using_namespace_directive does not contribute any new members to the underlying declaration space of the compilation unit or namespace, but, rather, affects only the compilation unit or namespace body in which it appears.

The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.

14.5.4 Использование статических директив

A using_static_directive imports the nested types and static members contained directly in a type declaration into the immediately enclosing compilation unit or namespace body, enabling the identifier of each member and type to be used without qualification.

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

Within member declarations in a compilation unit or namespace body that contains a using_static_directive, the accessible nested types and static members (except extension methods) contained directly in the declaration of the given type can be referenced directly.

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 доступны напрямую, поэтому метод N может ссылаться как на B элементы, так и M на элементы N1.A.

end example

A using_static_directive specifically does not import extension methods directly as static methods, but makes them available for extension method invocation (§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
        }
    }
}

the using_static_directive imports the extension method M contained in N1.A, but only as an extension method. Таким образом, первая ссылка M на текст результатов в результате ошибки во время компиляции B.N , так как именованные M элементы не находятся в области.

end example

A using_static_directive only imports members and types declared directly in the given type, not members and types declared in base classes.

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

the using_static_directive imports the method M2 contained in N1.B, but does not import the method M contained in N1.A. Таким образом, ссылка на M текст результатов в результате ошибки во время компиляции C.N , так как именованные M элементы не находятся в области. Разработчики должны добавить вторую using static директиву, чтобы указать, что методы в N1.A ней также должны быть импортированы.

end example

Ambiguities between multiple using_namespace_directives and using_static_directives are discussed in §14.5.3.

Объявления членов пространства имен 14.6

A namespace_member_declaration is either a namespace_declaration (§14.3) or a type_declaration (§14.7).

namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

A compilation unit or a namespace body can contain namespace_member_declarations, and such declarations contribute new members to the underlying declaration space of the containing compilation unit or namespace body.

Объявления типов 14.7

A type_declaration is a class_declaration (§15.2), a struct_declaration (§16.2), an interface_declaration (§18.2), an enum_declaration (§19.2), or a delegate_declaration (§20.2).

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

A type_declaration can occur as a top-level declaration in a compilation unit or as a member declaration within a namespace, class, or struct.

When a type declaration for a type T occurs as a top-level declaration in a compilation unit, the fully qualified name (§7.8.3) of the type declaration is the same as the unqualified name of the declaration (§7.8.2). When a type declaration for a type T occurs within a namespace, class, or struct declaration, the fully qualified name (§7.8.3) of the type declarationis S.N, where S is the fully qualified name of the containing namespace, class, or struct declaration, and N is the unqualified name of the declaration.

A type declared within a class or struct is called a nested type (§15.3.9).

The permitted access modifiers and the default access for a type declaration depend on the context in which the declaration takes place (§7.5.2):

  • Типы, объявленные в единицах компиляции или пространствах имен, могут иметь public или internal получать доступ. По умолчанию используется internal доступ.
  • Типы, объявленные в классах, могут иметь public, protected internal, protected, private protectedinternalили private доступ. По умолчанию используется private доступ.
  • Типы, объявленные в структуры, могут иметь publicinternalили private получить доступ. По умолчанию используется private доступ.

14.8 Квалифицированный псевдоним

14.8.1 General

Квалификатор :: пространства имен позволяет гарантировать, что поиск имен типа не влияет на новые типы и члены. Квалификатор пространства имен всегда отображается между двумя идентификаторами, называемыми идентификаторами слева и правой рукой. В отличие от обычного . квалификатора, левый идентификатор :: квалификатора выглядит только как экстерн или использует псевдоним.

A qualified_alias_member provides explicit access to the global namespace and to extern or using aliases that are potentially hidden by other entities.

qualified_alias_member
    : identifier '::' identifier type_argument_list?
    ;

A qualified_alias_member can be used as a namespace_or_type_name (§7.8) or as the left operand in a member_access (§12.8.7).

A qualified_alias_member consists of two identifiers, referred to as the left-hand and right-hand identifiers, seperated by the :: token and optionally followed by a type_argument_list. Если идентификатор слева является глобальным, глобальный пространство имен выполняется поиск правого идентификатора. For any other left-hand identifier, that identifier is looked up as an extern or using alias (§14.4 and §14.5.2). Ошибка во время компиляции возникает, если такой псевдоним отсутствует или псевдоним ссылается на тип. Если псевдоним ссылается на пространство имен, то для этого пространства имен выполняется поиск правого идентификатора.

A qualified_alias_member has one of two forms:

  • N::I<A₁, ..., Aₑ>, где N и I представляет идентификаторы и <A₁, ..., Aₑ> является списком аргументов типа. (e всегда один.)
  • N::I, где N и I представляет идентификаторы. (В этом случае e считается нулевой.)

Using this notation, the meaning of a qualified_alias_member is determined as follows:

  • Если N это идентификатор global, то глобальное пространство имен выполняется поиск по следующим причинам I:
    • If the global namespace contains a namespace named I and e is zero, then the qualified_alias_member refers to that namespace.
    • Otherwise, if the global namespace contains a non-generic type named I and e is zero, then the qualified_alias_member refers to that type.
    • Otherwise, if the global namespace contains a type named I that has e type parameters, then the qualified_alias_member refers to that type constructed with the given type arguments.
    • Otherwise, the qualified_alias_member is undefined and a compile-time error occurs.
  • Otherwise, starting with the namespace declaration (§14.3) immediately containing the qualified_alias_member (if any), continuing with each enclosing namespace declaration (if any), and ending with the compilation unit containing the qualified_alias_member, the following steps are evaluated until an entity is located:
    • If the namespace declaration or compilation unit contains a using_alias_directive that associates N with a type, then the qualified_alias_member is undefined and a compile-time error occurs.
    • Otherwise, if the namespace declaration or compilation unit contains an extern_alias_directive or using_alias_directive that associates N with a namespace, then:
      • If the namespace associated with N contains a namespace named I and e is zero, then the qualified_alias_member refers to that namespace.
      • Otherwise, if the namespace associated with N contains a non-generic type named I and e is zero, then the qualified_alias_member refers to that type.
      • Otherwise, if the namespace associated with N contains a type named I that has e type parameters, then the qualified_alias_member refers to that type constructed with the given type arguments.
      • Otherwise, the qualified_alias_member is undefined and a compile-time error occurs.
  • Otherwise, the qualified_alias_member is undefined and a compile-time error occurs.

Example: In the code:

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

Класс ссылается на этот классA, а тип global::A ссылается на System.Net.Sockets.Socket.S::Socket Использование A.x и S.Socket вместо этого приводило бы к ошибкам во время компиляции, так как A и S было бы разрешено к параметрам.

end example

Note: The identifier global has special meaning only when used as the left-hand identifier of a qualified_alias_name. It is not a keyword and it is not itself an alias; it is a contextual keyword (§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 этом объекте было бы разрешено.

Using global as the left-hand identifier of a qualified_alias_member always causes a lookup in the global namespace, even if there is a using alias named 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.A разрешает и MyGlobalTypes.Aglobal::A разрешает класс A в глобальном пространстве имен.

end note

14.8.2 Уникальность псевдонимов

Каждый блок компиляции и текст пространства имен имеет отдельное пространство объявлений для экстерн-псевдонимов и использование псевдонимов. Таким образом, в то время как имя экстерн-псевдонима или псевдонима должно быть уникальным в наборе экстерн-псевдонимов и использовать псевдонимы, объявленные в немедленном элементе компиляции или теле пространства имен, псевдоним может иметь то же имя, что и тип или пространство имен, если он используется только с квалификатором :: .

Example: In the following:

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 имеет два возможных значения во втором теле пространства имен, так как класс A и псевдоним A используются в области. По этой причине использование A в квалифицированном имени A.Stream неоднозначно и приводит к возникновению ошибки во время компиляции. Однако использование A с :: квалификатором не является ошибкой, так как A ищется только в качестве псевдонима пространства имен.

end example