Using c для чего
Директива #using (C++/CLI)
Импортирует метаданные в программу, скомпилированную с параметром/CLR.
Синтаксис
#using #using [ as_friend ]
Параметры
as_friend
Указывает, что все типы в файле доступны. Дополнительные сведения см. в разделе дружественные сборки (C++).
Комментарии
файл может представлять собой файл MSIL, который импортируется для управляемых данных и управляемых конструкций. Если библиотека DLL содержит манифест сборки, то импортируются все библиотеки DLL, на которые имеются ссылки в манифесте. Сборка, которую вы собираетесь создать, будет содержать файл в метаданных как ссылку на сборку.
Возможно, файл не содержит сборку (файл является модулем), и вы не собираетесь использовать информацию о типах из модуля в текущем приложении (сборка). Можно указать, что модуль является частью сборки с помощью /ASSEMBLYMODULE. После этого типы из этого модуля будут доступны любому приложению, ссылки на которые содержатся в этой сборке.
Компонент, на который имеется ссылка, #using может быть запущен с другой версией файла, импортированного во время компиляции, что приводит к непредсказуемым результатам в клиентском приложении.
Чтобы компилятор распознал тип в сборке (а не в модуле), необходимо принудительно разрешить тип. Например, можно принудительно определить экземпляр типа. Существуют и другие способы разрешения имен типов в сборке для компилятора. Например, при наследовании от типа в сборке имя типа будет называться компилятором.
Все импортированные типы (управляемые и собственные) в файле, на который ссылается, #using доступны, но компилятор обрабатывает собственные типы как объявления, а не определения.
При компиляции с параметром /clr ссылка на файл mscorlib.dll создается автоматически.
Компилятор ищет ссылки по следующему пути:
Путь, указанный в #using инструкции.
Каталоги, добавленные с помощью /AI параметра компилятора.
Каталоги, указанные в переменной среды LIBPATH.
Примеры
Можно создать сборку, которая ссылается на вторую сборку, которая сама ссылается на третью сборку. Необходимо явно ссылаться на третью сборку из первой, если вы явно используете один из ее типов.
6.12 – Объявления using и директивы using
Вы, наверное, видели эту программу во многих учебниках и учебных руководствах:
Некоторые старые компиляторы также начинают новые проекты с аналогичной программы.
Если вы это видите, бегите. Возможно, ваш учебник, руководство или компилятор устарели. В этом уроке мы выясним, почему.
Краткий урок истории
Перенесемся в сегодняшний день – если вы много используете стандартную библиотеку, набирание std:: перед всем, что вы используете из стандартной библиотеки, может стать повторяющейся рутиной, а в некоторых случаях может затруднить чтение вашего кода.
Но сначала давайте определим два термина.
Полные и неполные имена
Имя может быть полным или неполным.
Полное имя – это имя, которое включает в себя связанную область видимости. Чаще всего имена дополняются пространством имен с помощью оператора разрешения области видимости ( :: ). Например:
Для продвинутых читателей
Неполное имя – это имя, которое не включает в себя квалификатор области видимости. Например, cout и x являются неполными именами, поскольку они не включают связанную область видимости.
Объявления using
Директивы using
Вот снова наша программа Hello World с директивой using в строке 5:
Директивы using – это решение, которое было предоставлено для баз старого кода до пространства имен, которые использовали неполные имена для функций стандартной библиотеки. Вместо того, чтобы вручную обновлять каждое неполное имя до полного имени (что было рискованно), можно было бы разместить одну директиву using (т.е. using namespace std; ) в верхней части каждого файла, и все имена, которые были перемещены в пространство имен std всё еще можно было использовать неполными.
Проблемы с директивами using
Однако для современного кода C++ директивы using дают немного выгоды (экономия на вводе текста) по сравнению с риском.
Поскольку директивы using импортируют все имена из пространства имен (потенциально включая множество имен, которые вы никогда не будете использовать), вероятность возникновения конфликтов имен значительно возрастает (особенно, если вы импортируете пространство имен std ).
Для наглядности рассмотрим пример, в котором директивы using вызывают неоднозначность:
Вот еще один более коварный пример:
или использовалось объявление using вместо директивы using :
тогда наша программа вообще не имела бы никаких проблем.
Даже если директивы using не вызывают конфликтов имен сегодня, они делают код более уязвимым для будущих конфликтов. Например, если ваш код включает директиву using для какой-либо библиотеки, которая затем обновляется, все новые имена, представленные в обновленной библиотеке, теперь являются кандидатами на конфликты имен с вашим существующим кодом.
Может возникнуть и более коварная проблема. В обновленной библиотеке может появиться функция, которая не только имеет то же имя, но и лучше подходит для некоторых вызовов функций. В таком случае компилятор может решить отдать предпочтение новой функции, и поведение вашей программы неожиданно изменится.
Рассмотрим следующую программу:
Когда компилятор встречает вызов функции, он должен определить, с каким определением функции он должен сопоставить этот вызов. При выборе функции из набора потенциально совпадающих функций он предпочтет ту функцию, которая не требует преобразования аргументов, а не ту, которая требует преобразования аргументов. Поскольку литерал 0 принадлежит целочисленному типу, C++ предпочтет сопоставить someFcn(0) с недавно добавленной someFcn(int) (без преобразований), а не с someFcn(double) (требуется преобразование из int в double). Это вызывает неожиданное изменение результатов работы нашей программы.
Этого бы не произошло, если бы мы использовали объявление using или явный квалификатор области видимости.
Область видимости объявлений и директив using
Если объявление using или директива using используется в блоке, имена применимы только в этом блоке (они следуют обычным правилам области видимости блока). Это хорошо, поскольку снижает вероятность возникновения конфликтов имен внутри этого блока.
Если объявление using или директива using используются в глобальном пространстве имен, имена применимы ко всему остальному файлу (они имеют область видимости файла).
Отмена или замена инструкции using
После объявления инструкции using ее невозможно отменить или заменить ее другой инструкцией using в той области видимости, в которой она была объявлена.
Лучшее, что вы можете сделать, – это намеренно с самого начала ограничить область видимости инструкции using с помощью правил области видимости блока.
Конечно, всей этой головной боли можно избежать, в первую очередь, используя явным образом оператор разрешения области видимости ( :: ).
Лучшие практики для инструкций using
В современном C++ на самом деле нет места для использования директив. Они увеличивают вероятность коллизий имен сейчас и в будущем и могут вызывать более коварные проблемы. Хотя во многих учебниках и руководствах они широко используются, использования директив лучше вообще избегать.
Объявления using обычно считаются безопасными для использования внутри блоков. Ограничьте их использование в глобальном пространстве имен файлов исходного кода и никогда не используйте их в глобальном пространстве имен заголовочных файлов.
Лучшая практика
Директива using позволяет использовать типы, определенные в пространстве имен, без указания полного пространства имен этого типа. В базовой форме директива using импортирует все типы из одного пространства имен, как показано в следующем примере:
К директиве using можно применить два модификатора:
Оба модификатора можно применить вместе для импорта статических членов из определенного типа во всех исходных файлах проекта.
Теперь можно также создать псевдоним для пространства имен или типа, используя директиву псевдонимов using.
Модификатор global можно использовать в директиве using alias.
Ключевое слово using также используется для создания операторов using, которые помогают обеспечить правильную обработку объектов IDisposable, таких как файлы и шрифты. Дополнительные сведения об операторе using см. в разделе Оператор using.
Область директивы using без модификатора global ограничена файлом, в котором она находится.
Директива using может отображаться:
В противном случае возникнет ошибка компилятора CS1529.
Модификатор global
Добавление модификатора global к директиве using означает, что директива using должна применяться ко всем файлам в компиляции (обычно это проект). Директива global using впервые появилась в C# 10. Синтаксис:
где fully-qualified-namespace — это полное доменное имя пространства имен, на типы которого можно ссылаться без указания пространства имен.
Директива global using может находиться в начале любого файла исходного кода. Все директивы global using в одном файле должны предшествовать:
Директивы global using можно добавлять в любой исходный файл. Как правило, их хранят в одном месте. Порядок директив global using не имеет значения ни в одном файле, ни в нескольких.
Эти неявные директивы global using включают наиболее распространенные пространства имен для соответствующего типа проектов.
Директива using static указывает тип, доступ к статическим членам и вложенным типам которого можно получить, не указывая имя типа. Директива using static была представлена в C# версии 6. Синтаксис:
— это имя типа, на статические члены и вложенные типы которого можно ссылаться, не указывая имя типа. Если полное доменное имя (полное имя пространства имен вместе с именем типа) не указано, C# создает ошибку компилятора CS0246: «Тип или пространство имен ‘type/namespace’ не найдены (отсутствует директива using или ссылка сборки)».
Директива using static применяется к каждому типу, у которого есть статические члены (или вложенные типы), даже если при этом у него также имеются члены экземпляров. При этом для вызова членов экземпляров можно использовать только экземпляр типа.
Вы можете обращаться к статическим членам типа без необходимости квалификации доступа с помощью имени типа:
Обычно при вызове статического члена необходимо указать имя типа и имя нужного члена. Повторный ввод одного и того же имени типа для вызова относящихся к нему элементов может сделать код слишком длинным и сложным. Например, следующее определение класса Circle ссылается на многие члены класса Math.
Поскольку явно ссылаться на класс Math при каждой ссылке на член не требуется, директива using static создает более понятный код:
using static делает методы расширения, объявленные в указанном типе, доступными для поиска метода расширения. Тем не менее имена методов расширения не импортируются в область для неквалифицированной ссылки в коде.
Методы с тем же именем, импортированные из различных типов разными директивами using static в том же блоке компиляции или пространстве имен, формируют группу методов. Разрешение перегрузки в этих группах методов соответствует обычным правилам языка C#.
В следующем примере директива using static используется для того, чтобы доступ к статическим членам классов Console, Math и String можно было получать, не указывая имя типа.
В этом примере директива using static может также применяться к типу Double. Добавление этой директивы позволит вызывать метод TryParse(String, Double), не указывая имя типа. При этом, когда TryParse используется без указания имени типа, код становится менее понятным, поскольку появляется необходимость проверять директивы using static и определять, какой метод числового типа TryParse вызывается.
Псевдоним using
В следующем примере показано, как задать и использовать псевдоним using для пространства имен.
В следующем примере показано, как задать директиву using и псевдоним using для класса.
Использование пространства имен My из Visual Basic
Дополнительные сведения об использовании пространства имен MyServices из Visual Basic см. в разделе Разработка с использованием пространства имен My.
Необходимо добавить ссылку на сборку Microsoft.VisualBasic.dll в проект. Некоторые классы из пространства имен MyServices нельзя вызывать из приложения C#, как, например, несовместимый класс FileSystemProxy. Конкретно в этом случае вместо него можно использовать статические методы из состава FileSystem (также входит в библиотеку VisualBasic.dll). Например, ниже показано, как дублировать каталог с помощью одного из таких методов:
Спецификация языка C#
Дополнительные сведения см. в разделе Директивы using в статье Спецификация языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Дополнительные сведения об использовании модификатора global using см. в спецификации функции global using — C# 10.
Оператор using (справочник по C#)
Предоставляет удобный синтаксис, обеспечивающий правильное использование объектов IDisposable. Начиная с C# 8.0 инструкция using гарантирует правильное использование объектов IAsyncDisposable.
Пример
Начиная с версии C# 8.0, можно использовать следующий альтернативный синтаксис для оператора using без использования фигурных скобок:
Примечания
File и Font представляют собой примеры управляемых типов, которые обращаются к неуправляемым ресурсам (в данном случае это обработчики файлов и контексты устройств). Существуют и многие другие виды неуправляемых ресурсов и типов библиотек классов, которые их инкапсулируют. Все эти типы должны реализовывать интерфейс IDisposable или интерфейс IAsyncDisposable.
Новый синтаксис инструкции using преобразуется в похожий код. Блок try открывается там, где объявлена переменная. Блок finally добавляется в конец охватывающего блока, как правило, в конце метода.
В одной инструкции using можно объявить сразу несколько экземпляров типа, как показано в следующем примере. Обратите внимание, что невозможно использовать неявно типизированные переменные ( var ) при объявлении нескольких переменных в одной инструкции:
Несколько объявлений одного типа можно объединить с помощью нового синтаксиса, представленного в C# 8, как показано в следующем примере:
Дополнительные сведения об утилизации объектов IDisposable см. в разделе Использование объектов, реализующих IDisposable.
Спецификация языка C#
Дополнительные сведения см. в разделе Оператор using в статье Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
using Объявление вводит имя в декларативную область, в которой отображается объявление using.
Синтаксис
Параметры
спецификатор вложенного имени Последовательность пространств имен, классов или перечислений, а также операторы разрешения области (::), заканчивающиеся оператором разрешения области. Чтобы ввести имя из глобального пространства имен, можно использовать один оператор разрешения области. Ключевое слово typename является необязательным и может использоваться для разрешения зависимых имен при их внедрении в шаблон класса из базового класса.
неполный идентификатор Неполное выражение идентификатора, которое может представлять собой идентификатор, имя перегруженного оператора, определяемый пользователем литеральный оператор или имя функции преобразования, Имя деструктора класса или имя шаблона и список аргументов.
декларатор-список Разделенный запятыми список описателей сквалификаторами неполного имени ([]) с разделителем-запятой, за которым следует, по желанию, многоточие.
Комментарии
Пример: using объявление в поле класса
Объявление using может использоваться в определении класса.
Пример: using объявление объявления элемента
Если объявление using объявляет член, оно должно ссылаться на член базового класса.
Пример: using объявление с явной квалификацией
На члены, объявленные с помощью объявления using, можно ссылаться с помощью явной квалификации. Префикс :: указывает на глобальное пространство имен.
Пример: using объявления синонимы и псевдонимы
Если используется объявление using, то созданный им синоним указывает только на определения, которые являются действительными в точке его создания. Определения, добавляемые в пространство имен после объявления using, не являются допустимыми синонимами.
Имя, определенное using объявлением, является псевдонимом для его исходного имени. Оно не влияет на тип, компоновку и другие атрибуты исходного объявления.
Пример. локальные объявления и using объявления
Говоря о функциях в пространствах имен, если в области объявления задан набор локальных объявлений и объявлений using для одного имени, то все они должны указывать на одну и ту же сущность, либо же все они должны указывать на функции.
Пример: объявления локальных функций и using объявления
Локальное объявление функции не может иметь такое же имя и тип, что и функция, введенная в код объявлением using. Пример:
Пример: using объявление и наследование
Говоря о наследовании, когда объявление using вводит имя из базового класса в область видимости производного класса, то функции-члены из производного класса переопределяют виртуальные функции-члены из базового класса, имеющие такое же имя и типы аргументов.
Пример: using Специальные возможности объявления
Все экземпляры имени, упоминаемого в объявлении using, должны быть доступны. В частности, если объявление using используется в производном классе для доступа к базовому классу, то имя члена должно быть доступно. Если имя относится к перегруженной функции-члену, то все функции с этим именем должны быть доступны.
Дополнительные сведения о специальных возможностях членов см. в разделе Управление доступом кчленам.