Пространства имен

43

Прежде чем углубляться в детали развертывания и конфигурирования сборок, сначала необходимо узнать о том, как создавать специальные пространства имен в .NET. При создании собственных приложений, однако, может быть удобно группировать свои взаимосвязанные типы в специальные пространства имен. В C# это делается с помощью ключевого слова namespace. Определение специальных пространств имен явным образом начинает играть даже еще более важную роль при создании dll-сборок в .NET, поскольку другие разработчики должны иметь возможность импортировать эти специальные пространства имен, чтобы использовать содержащиеся в них типы.

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

Ниже приведена общая форма объявления пространства имен:

namespace имя {
// члены
}

Давайте рассмотрим пример:

using System;

// Объявляем новое пространство имен, описывающее классы фигур
// Файл MyShapes.cs
namespace ShapesMyProgramm
{
    class Circle
    {
        public double Radius { get; set; }
        
        public Circle(double r) 
        {
            Radius = r;
        }

        public void Square()
        {
            Console.WriteLine("Площадь круга = {0:#.###}",Math.PI*Radius*Radius);
        }

        public void Long()
        {
            Console.WriteLine("Длина круга = {0:#.##}",Math.PI*2*Radius);
        }
    }

    class Rectangle
    {
        public int a { get; set; }
        public int b { get; set; }

        public Rectangle(int a, int b)
        {
            this.a = a;
            this.b = b;
        }

        public void Square()
        {
            Console.WriteLine("Площадь прямоугольника = "+a*b);
        }

        public void Long()
        {
            Console.WriteLine("Длина прямоугольника = "+(2*a+2*b));
        }
    }
}
// Файл Program.cs
using System;
using ShapesMyProgramm; // Используем объявленное пространство имен

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            Circle c1 = new Circle(r: 12.0);
            Rectangle rec1 = new Rectangle(a: 5, b: 4);

            c1.Square();
            c1.Long();
            rec1.Square();
            rec1.Long();
            Console.ReadLine();
        }
    }
}
Использование дополнительного пространства имен

В этом примере предполагается, что файл (или файлы) с кодом C#, в котором содержится определение пространства имен ShapesMyProgramm, является частью того же проекта типа Console Application, что и файл с определением пространства имен ConsoleApplication1. Другими словами, все эти файлы будут использоваться для компиляции единственной исполняемой сборки .NET.

Если пространство имен ShapesMyProgramm определено внутри какой-то внешней сборки, для успешной компиляции может потребоваться добавить ссылку на эту библиотеку.

Предотвращение конфликтов имен с помощью пространств имен

С технической точки зрения применять в C# ключевое слово using при ссылках на типы, определенные во внешних пространствах имен, вовсе не требуется. Вместо этого можно использовать полностью уточненное имя типа, под которым понимается имя типа с идущим перед ним в качестве префикса названием пространства имен, где этот тип определен. Так код файла Program.cs можно видоизменить следующим образом:

static void Main()
        {
            ShapesMyProgramm.Circle c1 = new ShapesMyProgramm.Circle(r: 12.0);
            ShapesMyProgramm.Rectangle rec1 = new ShapesMyProgramm.Rectangle(a: 5, b: 4);

            c1.Square();
            c1.Long();
            rec1.Square();
            rec1.Long();
            Console.ReadLine();
        }

Обычно необходимости в применении полностью уточненного имени не возникает. Это требует большего объема клавиатурного ввода, при этом никак не влияет на размер и скорость выполнения кода. С другой стороны, в CIL-коде типы всегда определяются с использованием полностью уточненных имен. В результате применение в C# ключевого слова using, по сути, позволяет просто экономить время.

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

В C# ключевое слово using также позволяет создавать псевдоним для полностью уточненного имени типа. В этом случае определяется маркер, на месте которого во время компиляции должно подставляться полностью уточненное имя. Определение псевдонимов является вторым способом разрешения конфликтов на уровне имен:

// Файл Program.cs
using System;
// Создание псевдонима
using ShapeCircle = ShapesMyProgramm.Circle;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            // Использование псевдонима
            ShapeCircle c1 = new ShapesMyProgramm.Circle(r: 12.0);
            ShapesMyProgramm.Rectangle rec1 = new ShapesMyProgramm.Rectangle(a: 5, b: 4);

            c1.Square();
            c1.Long();
            rec1.Square();
            rec1.Long();
            Console.ReadLine();
        }
    }
}

Ключевое слово using в C# позволяет создавать псевдонимы для длинных полностью уточненных имен и потому может применяться для разрешения конфликтов на уровне имен, которые могут возникать в результате импорта пространств имен, содержащих типы с идентичными именами.

Применение описателя псевдонима пространства имен

Пространства имен помогают предотвратить конфликты имен, но не устранить их полностью. Такой конфликт может, в частности, произойти, когда одно и то же имя объявляется в двух разных пространствах имен и затем предпринимается попытка сделать видимыми оба пространства. Допустим, что два пространства имен содержат класс MyClass. Если попытаться сделать видимыми оба пространства имен с помощью директивы using, то имя MyClass из первого пространства вступит в конфликт с именем MyClass из второго пространства, обусловив появление ошибки неоднозначности. В таком случае для указания предполагаемого пространства имен явным образом можно воспользоваться описателем псевдонима пространства имен ::.

Ниже приведена общая форма оператора ::.

псевдоним_пространства_имен :: идентификатор

Здесь псевдоним_пространства_имен обозначает конкретное имя псевдонима пространства имен, а идентификатор — имя члена этого пространства.

Лучший чат для C# программистов