Menu

Директива using и пространства имён в C#: псевдонимы, using static, global using

Как пространства имён в C# организуют типы и как директива using их импортирует: псевдонимы, using static, полные имена, исправление неоднозначных ссылок, global using и пространства имён на уровне файла.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

У каждого типа в .NET есть полное имя, которое состоит из пространства имён и имени типа: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. Пространства имён группируют связанные типы и не дают именам конфликтовать, поэтому ваш собственный класс Order или Timer может сосуществовать с классами из библиотек. Директива using в начале файла импортирует пространство имён, чтобы можно было пользоваться короткими именами.

Вывод:

Cart: tea, honey
1

Директива using влияет только на имена при компиляции. Она не загружает библиотеку и не добавляет код в программу; какие библиотеки доступны, определяют ссылки проекта и пакеты NuGet. Если компилятор сообщает, что тип или пространство имён «could not be found (are you missing a using directive or an assembly reference?)», ошибка CS0246, значит, либо нет строки using, либо на пакет нет ссылки.

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

Помещайте типы внутрь блока namespace. Пространства имён могут быть вложенными и записываться через точку, а одно и то же пространство имён может быть разнесено по многим файлам.

Вывод:

120.00 via DHL
Shop.Billing.Invoice

namespace Shop.Billing { } это сокращение для namespace Shop { namespace Billing { } }. Код внутри Shop может обращаться к Billing.Invoice без префикса Shop., потому что имена сначала ищутся в объемлющих пространствах имён.

Соглашения: начинайте с названия компании или продукта (Contoso.Payments), затем указывайте функцию или слой и повторяйте структуру папок (Contoso.Payments/Refunds/RefundService.cs содержит Contoso.Payments.Refunds). Никогда не называйте класс так же, как его пространство имён (Shop.Shop): это вынуждает везде писать неудобные полные имена.

Псевдонимы

using Name = Namespace.Type; даёт типу (или пространству имён) локальное имя. Это нужно в двух ситуациях: чтобы сократить длинный обобщённый тип и чтобы разрешить конфликт имён.

Вывод:

latte: 3.60
order 17

Псевдонимы действуют только в файле, где они объявлены (если они не global, см. ниже). В C# 12 и новее псевдоним может обозначать любой тип, включая кортежи и массивы: using Point = (int X, int Y);.

Неоднозначные ссылки (CS0104)

Когда в двух импортированных пространствах имён есть тип с одинаковым именем, использование короткого имени становится ошибкой. Классический случай Timer, который существует в System.Threading, System.Timers и (в настольных приложениях) System.Windows.Forms:

using System.Threading;
using System.Timers;

var t = new Timer(1000);
// error CS0104: 'Timer' is an ambiguous reference between
// 'System.Timers.Timer' and 'System.Threading.Timer'

Три способа исправить, от самого локального к наименее локальному: написать полное имя (new System.Timers.Timer(1000)), добавить псевдоним, который указывает, какой тип имеется в виду, или удалить ненужную директиву.

Вывод:

250
System.Timers.Timer
System.Threading.Timer

Если ваше собственное пространство имён определяет тип с именем System или Console, префикс global:: заставляет искать имя от корня: global::System.Console.WriteLine("hi");. По этой причине сгенерированный код использует его повсюду.

using static

using static импортирует статические члены одного типа, чтобы их можно было вызывать без имени типа. Это удобно в коде, который снова и снова вызывает один и тот же класс, например Math:

Вывод:

Area: 28.27
Hypotenuse: 5
42

using static работает также с перечислениями (using static System.DayOfWeek; позволяет писать Monday) и с вашими собственными статическими классами. Используйте его там, где короткие имена остаются однозначными; одинокий WriteLine в большом файле может заставить читателя гадать, что именно пишет.

global using и пространства имён на уровне файла (C# 10)

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

// GlobalUsings.cs, C# 10 and later
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Money = System.Decimal;

Проекты SDK на .NET 6 и новее могут генерировать их сами. С <ImplicitUsings>enable</ImplicitUsings> в .csproj (по умолчанию в новых шаблонах) консольный проект получает System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading и System.Threading.Tasks; веб-проекты дополнительно получают пространства имён ASP.NET Core. Поэтому современные файлы Program.cs сразу начинаются с кода.

Пространство имён на уровне файла объявляет пространство имён для всего файла с точкой с запятой вместо блока, что экономит один уровень отступа:

// C# 10 and later
namespace Shop.Billing;

public class Invoice
{
    public decimal Amount { get; set; }
}

В файле может быть только одно пространство имён на уровне файла, и его нельзя смешивать с блочными пространствами имён в том же файле. Старые проекты, скрипты Unity и код под .NET Framework используют блочную форму, показанную выше.

Где располагаются директивы using и оператор using

Директивы using должны идти до любых объявлений пространств имён или типов в файле (глобальные using раньше всего остального). Их также можно поместить внутрь блока namespace, и тогда они действуют только там; руководства по стилю расходятся, но большая часть кода .NET держит их в начале файла.

У ключевого слова using есть вторая, не связанная с первой роль внутри методов: оператор using using (var file = File.OpenRead(path)) { ... } вызывает Dispose у объекта в конце блока, закрывая файлы и подключения. Общее у них только ключевое слово. См. страницу оператор using.

Часто задаваемые вопросы

Что делает using в C#?

В начале файла using System.Text; это директива, которая импортирует пространство имён, чтобы вместо System.Text.StringBuilder можно было писать StringBuilder. Она не добавляет кода и ничего не загружает, а только сокращает имена. Внутри метода using (var f = ...) это другая возможность, оператор using, который освобождает объект в конце блока.

Что такое пространство имён в C#?

Пространство имён (namespace) это именованная группа типов, которая предотвращает конфликты имён и упорядочивает код, например System.Collections.Generic или MyShop.Billing. Два класса могут называться одинаково, если они находятся в разных пространствах имён. По соглашению пространства имён повторяют структуру папок и начинаются с названия компании или продукта.

Что такое using static в C#?

using static System.Math; импортирует статические члены одного типа, поэтому можно вызывать Sqrt(16) и читать PI без префикса Math.. Это работает с любым классом, включая ваши собственные и перечисления. Используйте его там, где короткие имена остаются понятными, например в коде с большим количеством математики.

Как исправить ошибку «is an ambiguous reference» в C#?

Ошибка CS0104 означает, что в двух импортированных пространствах имён есть тип с таким именем, например Timer в System.Threading и System.Timers. Напишите полное имя (System.Timers.Timer), удалите одну из директив using или добавьте псевдоним: using Timer = System.Timers.Timer;.

Что такое global using в C#?

global using System.Text; (C# 10) импортирует пространство имён для всех файлов проекта, а не только для того, где он написан. Проекты SDK на .NET 6 и новее автоматически генерируют набор глобальных using, когда задано <ImplicitUsings>enable</ImplicitUsings>, поэтому в новых файлах Program.cs нет строк using.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ