Перейти к содержимому

Using c что это

  • автор:

оператор using — обеспечение правильного использования удаленных объектов

Инструкция using гарантирует правильное использование экземпляра IDisposable :

var numbers = new List(); using (StreamReader reader = File.OpenText("numbers.txt")) < string line; while ((line = reader.ReadLine()) is not null) < if (int.TryParse(line, out int number)) < numbers.Add(number); >> > 

Когда элемент управления покидает блок инструкции using , полученный IDisposable экземпляр удаляется. В частности, инструкция гарантирует, что удаленный экземпляр удаляется даже в том случае, using если исключение возникает в блоке using инструкции. В предыдущем примере открытый файл закрывается после обработки всех строк.

Используйте инструкцию await using для правильного использования экземпляра IAsyncDisposable :

await using (var resource = new AsyncDisposableExample()) < // Use the resource >

Дополнительные сведения об использовании экземпляров см. в разделе «Использование асинхронногоIAsyncDisposable удаления» статьи «Реализация метода DisposeAsync».

Вы также можете использовать using объявление , которое не требует фигурных скобок:

static IEnumerable LoadNumbers(string filePath) < using StreamReader reader = File.OpenText(filePath); var numbers = new List(); string line; while ((line = reader.ReadLine()) is not null) < if (int.TryParse(line, out int number)) < numbers.Add(number); >> return numbers; > 

При объявлении using локальная переменная удаляется в конце область, в которой она объявлена. В предыдущем примере удаление происходит в конце метода.

Переменная, объявленная оператором или объявлением using , является чтением. Его нельзя переназначить или передать в качестве ref параметра out .

Можно объявить несколько экземпляров одного типа в одной using инструкции, как показано в следующем примере:

using (StreamReader numbersFile = File.OpenText("numbers.txt"), wordsFile = File.OpenText("words.txt")) < // Process both files >

При объявлении нескольких экземпляров в одном using операторе они удаляются в обратном порядке объявления.

Вы также можете использовать инструкцию using и объявление с экземпляром структуры ссылок, которая соответствует шаблону удаления. То есть он имеет метод экземпляра Dispose , который доступен, без параметров и имеет тип возвращаемого void значения.

Оператор using также может иметь следующую форму:

using (expression) < // . >

где expression создается удаленный экземпляр. Это показано в следующем примере:

StreamReader reader = File.OpenText(filePath); using (reader) < // Process file content >

В предыдущем примере после того, как элемент управления покидает инструкцию using , удаленный экземпляр остается в область пока он уже удален. Если этот экземпляр используется дальше, может возникнуть исключение, например ObjectDisposedException. Поэтому рекомендуется объявлять удаленную переменную в using инструкции или с объявлением using .

Спецификация языка C#

См. также

  • справочник по C#
  • System.IDisposable
  • System.IAsyncDisposable
  • Использование объектов, реализующих IDisposable
  • Реализация метода Dispose
  • Реализация метода DisposeAsync
  • Использование простого оператора using (правило стиля IDE0063)
  • using Директива

Совместная работа с нами на GitHub

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

Пространства имен (C++)

Пространство имен — это декларативная область, в рамках которой определяются различные идентификаторы (имена типов, функций, переменных, и т. д.). Пространства имен используются для организации кода в виде логических групп и с целью избежания конфликтов имен, которые могут возникнуть, особенно в таких случаях, когда база кода включает несколько библиотек. Все идентификаторы в пределах пространства имен доступны друг другу без уточнения. Идентификаторы за пределами пространства имен могут получить доступ к членам с помощью полного имени для каждого идентификатора, например, с помощью объявления для одного идентификатора ( using std::string ) или директивы using для всех идентификаторов в пространстве имен ( using namespace std; ). std::vector vec; Код в файлах заголовков всегда должен содержать полное имя в пространстве имен.

В следующем примере показано объявление пространства имен и продемонстрированы три способа доступа к членам пространства имен из кода за его пределами.

namespace ContosoData < class ObjectManager < public: void DoSomething() <>>; void Func(ObjectManager) <> > 

Использование полного имени:

ContosoData::ObjectManager mgr; mgr.DoSomething(); ContosoData::Func(mgr); 

Чтобы добавить в область видимости один идентификатор, используйте объявление using:

using ContosoData::ObjectManager; ObjectManager mgr; mgr.DoSomething(); 

Чтобы добавить в область видимости все идентификаторы пространства имен, используйте директиву using:

using namespace ContosoData; ObjectManager mgr; mgr.DoSomething(); Func(mgr); 

Директивы using

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

Директиву using можно поместить в верхнюю часть CPP-файла (в области видимости файла) или внутрь определения класса или функции.

Без особой необходимости не размещайте директивы using в файлах заголовков (*.h), так как любой файл, содержащий этот заголовок, добавит все идентификаторы пространства имен в область видимости, что может вызвать скрытие или конфликты имен, которые очень трудно отлаживать. В файлах заголовков всегда используйте полные имена. Если эти имена получаются слишком длинными, используйте псевдоним пространства имен для их сокращения. (См. ниже.)

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

Как правило, пространство имен объявляется в файле заголовка. Если реализации функций находятся в отдельном файле, определяйте имена функций полностью, как показано в следующем примере.

// contosoData.h #pragma once namespace ContosoDataServer

Реализации функций в contosodata.cpp должны использовать полное имя, даже если директива using размещается в верхней части файла:

#include "contosodata.h" using namespace ContosoDataServer; void ContosoDataServer::Foo() // use fully-qualified name here < // no qualification needed for Bar() Bar(); >int ContosoDataServer::Bar()

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

Члены именованного пространства имен можно определить вне пространства имен, в котором они объявлены явным определением имени. Однако определение должно располагаться после точки объявления в пространстве имен, окружающем то пространство имен, где находится объявление. Например:

// defining_namespace_members.cpp // C2039 expected namespace V < void f(); >void V::f() < >// ok void V::g() < >// C2039, g() is not yet a member of V namespace V

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

Глобальное пространство имен

Если идентификатор не объявлен явно в пространстве имен, он неявно считается входящим в глобальное пространство имен. Как правило, старайтесь избегать объявления в глобальном область, если это возможно, за исключением основной функции точки входа, которая должна находиться в глобальном пространстве имен. Чтобы явно указать глобальный идентификатор, используйте оператор разрешения области видимости без имени, как сделано в ::SomeFunction(x); . Это позволит отличать данный идентификатор от любого другого элемента с таким же именем, находящегося в другом пространстве имен. Кроме того, это облегчит понимание кода.

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

Все стандартные типы и функции библиотек C++ объявляются в std пространстве имен или пространствах имен, вложенных внутри std .

Вложенные пространства имен

Пространства имен могут быть вложенными. Обычное вложенное пространство имен имеет неквалифицированный доступ к членам родительского элемента, но родительские члены не имеют неквалифицированного доступа к вложенному пространству имен (если он не объявлен как встроенный), как показано в следующем примере:

namespace ContosoDataServer < void Foo(); namespace Details < int CountImpl; void Ban() < return Foo(); >> int Bar(); int Baz(int i) < return Details::CountImpl; >> 

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

Встроенные пространства имен (C++11)

В отличие от обычных вложенных пространств имен члены встроенного пространства имен обрабатываются как члены родительского пространства имен. Эта особенность позволяет выполнять поиск перегруженных функций с зависимостью от аргументов среди функции, которые имеют перегрузки в родительском и вложенном встроенном пространстве имен. Это также позволяет объявлять специализации в родительском пространстве имен для шаблонов, объявленных во встроенном пространстве имен. В следующем примере показано, как внешний код привязывается к встроенному пространству имен по умолчанию.

// Header.h #include namespace Test < namespace old_ns < std::string Func() < return std::string("Hello from old"); >> inline namespace new_ns < std::string Func() < return std::string("Hello from new"); >> > // main.cpp #include "header.h" #include #include int main() < using namespace Test; using namespace std; string s = Func(); std::cout 

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

namespace Parent < inline namespace new_ns < template struct C < T member; >; > template<> class C <>; > 

Встроенные пространства имен можно использовать как механизм управления версиями для управления изменениями в открытом интерфейсе библиотеки. Например, можно создать одно родительское пространство имен и инкапсулировать каждую версию интерфейса в своем собственном пространстве имен, вложенном в родительское. Пространство имен, которое содержит самую последнюю или основную версию, квалифицируется как встроенное и поэтому представляется так, будто оно является непосредственным членом родительского пространства имен. Клиентский код, вызывающий Parent::Class, автоматически привязывается к новому коду. Клиенты, которые предпочитают использовать старую версию, могут по-прежнему получить доступ к ней, используя полный путь к вложенному пространству имен, содержащему данный код.

Ключевое слово inline должно применяться к первому объявлению пространства имен в единице компиляции.

В следующем примере показано две версии интерфейса: каждое — во вложенном пространстве имен. Пространство имен v_20 содержит некоторые изменения из интерфейса v_10 и помечается как встроенное. Клиентский код, который использует новую библиотеку и вызывает Contoso::Funcs::Add , вызовет версию v_20. Код, который пытается вызвать Contoso::Funcs::Divide , теперь будет вызывать ошибку времени компиляции. Если действительно требуется эта функция, доступ к версии v_10 можно получить путем явного вызова Contoso::v_10::Funcs::Divide .

namespace Contoso < namespace v_10 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); T Divide(T a, T b); >; > inline namespace v_20 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); std::vectorLog(double); T Accumulate(std::vector nums); >; > > 

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

Имена пространств имен должны быть уникальными, из-за чего зачастую они получаются не слишком короткими. Если длина имени затрудняет чтение кода или утомительно вводить в файл заголовка, где нельзя использовать директивы, можно сделать псевдоним пространства имен, который служит сокращенным для фактического имени. Например:

namespace a_very_long_namespace_name < class Foo <>; > namespace AVLNN = a_very_long_namespace_name; void Bar(AVLNN::Foo foo)

анонимные или безымянные пространства имен

Вы можете создать явное пространство имен, но не присвоить ему имя.

namespace < int MyFunc()<>> 

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

Урок №54. using-стейтменты

Если вы часто используете Стандартную библиотеку C++, то постоянное добавление std:: к используемым объектам может быть несколько утомительным, не правда ли? Язык C++ предоставляет альтернативы в виде using-стейтментов.

Оглавление:

  1. Использование «using-объявления»
  2. Использование «using-директивы»
  3. Пример конфликта c «using-директивой»
  4. Область видимости «using-объявления» и «using-директивы»
  5. Отмена/замена using-стейтментов

Использование «using-объявления»

Одной из альтернатив является использование «using-объявления». Вот программа «Hello, world!» с «using-объявлением» в строке №5:

using std :: cout ; // "using-объявление" сообщает компилятору, что cout следует обрабатывать, как std::cout

cout << "Hello, world!" ; // и никакого префикса std:: уже здесь не нужно!

Строка using std::cout; сообщает компилятору, что мы будем использовать объект cout из пространства имен std. И каждый раз, когда компилятор будет сталкиваться с cout , он будет понимать, что это std::cout .

Конечно, в этом случае мы не сэкономили много усилий, но в программе, где объекты из пространства имен std используются сотни, если не тысячи раз, «using-объявление» неплохо так экономит время, усилия и улучшает читабельность кода. Также для каждого объекта нужно использовать отдельное «using-объявление» (например, отдельное для std::cout , отдельное для std::cin и отдельное для std::endl ).

Хотя этот способ является менее предпочтительным, чем использование префикса std:: , он все же является абсолютно безопасным и приемлемым.

Использование «using-директивы»

Второй альтернативой является использование «using-директивы». Вот программа «Hello, world!» с «using-директивой» в строке №5:

using namespace std ; // "using-директива" сообщает компилятору, что мы используем все объекты из пространства имен std!

cout << "Hello, world!" ; // так что никакого префикса std:: здесь уже не нужно!

Много разработчиков спорят насчет использования «using-директивы». Так как с её помощью мы подключаем ВСЕ имена из пространства имен std, то вероятность возникновения конфликтов имен значительно возрастает (но все же эта вероятность в глобальном масштабе остается незначительной). using namespace std; сообщает компилятору, что мы хотим использовать всё, что находится в пространстве имен std, так что, если компилятор найдет имя, которое не сможет распознать, он будет проверять его наличие в пространстве имен std.

Совет: Старайтесь избегать использования «using-директивы» (насколько это возможно).

Пример конфликта c «using-директивой»

Рассмотрим пример, где использование «using-директивы» создает неопределенность:

int cout ( ) // объявляем нашу собственную функцию "cout"
using namespace std ; // делаем std::cout доступным по "cout"

cout

Здесь компилятор не сможет понять, использовать ли ему std::cout или функцию cout(), которую мы определили сами. В результате, получим ошибку неоднозначности. Хоть это и банальный пример, но если бы мы добавили префикс std:: к cout:

std :: cout << "Hello, world!" ; // сообщаем компилятору, что хотим использовать std::cout

Или использовали бы «using-объявление» вместо «using-директивы»:

using std :: cout ; // сообщаем компилятору, что cout означает std::cout
cout << "Hello, world!" ; // так что здесь следует использовать std::cout

Тогда наша программа была бы без ошибок.

Большинство программистов избегают использования «using-директивы» именно по этой причине. Другие считают это приемлемым до тех пор, пока «using-директива» используется только в пределах отдельных функций (что значительно сокращает масштабы возникновения конфликтов имен).

Области видимости «using-объявления» и «using-директивы»

Если «using-объявление» или «using-директива» используются в блоке, то они применяются только внутри этого блока (по обычным правилам локальной области видимости). Это хорошо, поскольку уменьшает масштабы возникновения конфликтов имен до отдельных блоков. Однако многие начинающие программисты пишут «using-директиву» в глобальной области видимости (вне функции main() или вообще вне любых функций). Этим они вытаскивают все имена из пространства имен std напрямую в глобальную область видимости, значительно увеличивая вероятность возникновения конфликтов имен. А это уже не хорошо.

Правило: Никогда не используйте using-стейтменты вне тела функций.

Отмена/замена using-стейтментов

Как только один using-стейтмент был объявлен, его невозможно отменить или заменить другим using-стейтментом в пределах области видимости, в которой он был объявлен. Например:

Using c что это

При чтении и записи в предыдущих темах использовались объекты std::cout и std::cin соответственно. Причем они использовались с префиксом std:: . Этот префикс указывает, что объекты cout, cin, endl определены в пространстве имен std . А само двойное двоеточие :: представляет оператор области видимости (scope operator), который позволяет указать, в каком пространстве имен определен объект. И без префикса эти объекты по умолчанию мы использовать не можем.

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

Использование оператора using имеет следующий формат:

using пространство_имен::объект

Например, пусть у нас есть следующая программа:

#include int main() < int age; std::cout > age; std::cout

Здесь используются сразу три объекта из пространства имен std : cout , cin и endl . Перепишем программу с использованием using:

#include using std::cin; using std::cout; using std::endl; int main() < int age; cout > age; cout

Для каждого объекта из пространства std определяется свое выражение using. При этом программа будет работать также как и раньше.

Определение псевдонимов

Ключевое слово using также позволяет определять псевдонимы для типов. Это может пригодиться, когда мы работаем с типами с длинными названиями, а определение коротких псевдонимов позволит сократить код. Например:

#include using ullong = unsigned long long; int main() < ullong n ; std::cout

В данном случае для типа unsigned long long определен псевдоним ullong . Стоит отметить, что это именно определение псевдонима, а НЕ определение нового типа.

Стоит отметить, что для определения псевдонимов в С++ также может использоваться старый подход в стиле языка С с помощью оператора typedef :

#include typedef unsigned long long ullong; int main() < ullong n ; std::cout

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *