Существуют ли особые случаи, когда я должен (или не должен?) использовать "использование" блоков:
using(SomeType t = new SomeType()){
...
}
Существуют ли особые случаи, когда я должен (или не должен?) использовать "использование" блоков:
using(SomeType t = new SomeType()){
...
}
Когда класс SomeType
реализует IDisposable
.
Некоторые объекты нуждаются в некоторых действиях, которые необходимо предпринять, когда вы закончите с ними. Обычно это происходит потому, что объект использует какой-то ресурс, который нужно утилизировать. Например, если у вас есть файловый объект класса File, и этот объект открывает файл из файловой системы, файл в файловой системе должен быть снова закрыт.
Если вы только что покинули объект файла и забыли вызвать файл .Close(), он не будет очищен до тех пор, пока не будет запущен сборщик Garbage Collector (GC) и ничего не будет работать с файловым объектом. Когда запускается сборщик мусора, он должен быть оставлен на время выполнения Common Language Runtime (CLR). Если GC не запускается довольно долго после того, как вы закончили с файлом, файл может оставаться открытым потенциально в течение длительного времени. Это может представлять большую проблему, если есть много файловых объектов или если что-то хочет открыть файл, но не может, потому что оставшийся объект файла все еще висит вокруг.
Чтобы решить эту проблему, С# имеет интерфейс IDisposable. У этого метода есть метод Dispose. Классы, требующие некоторой очистки, реализуют этот метод Dispose. Это дает вам стандартный способ очистки любых объектов, использующих ресурсы. Существует много классов, которым необходимо вызвать Dispose. Проблема заключается в том, что код распространяется на вызовы Dispose, и им сложно следовать, потому что место, где вы новичок в объекте, и вызываете Dispose для его очистки, различны. Таким образом, вам пришлось много оглядеть код и быть очень осторожным, чтобы проверить, были ли вызовы Dispose в нужном месте.
Чтобы решить эту проблему, С# представила ключевое слово 'using'. Вы можете поместить ключевое слово 'using', где вы новый объект, и это гарантирует, что Dispose будет вызван на него для вас. Это гарантирует, что Dispose будет вызываться независимо от того, что произойдет... даже если есть исключение, выведенное внутри тела оператора using.
Итак, вы должны использовать "использование", когда хотите убедиться, что объект, который выделяет ресурсы, будет очищен.
использование может использоваться только для объектов, объявленных в стеке, то есть в функции. Он не работает для объектов, объявленных как члены класса. Для них вы должны вызвать Dispose самостоятельно. Возможно, вам придется реализовать Dispose в своем классе, чтобы он мог вызывать Dispose на любых объектах-членах, которые ему требуются.
Обычными объектами, которые нужно использовать вызываемые на них, являются: Файлы, подключения к базе данных, объекты графики, такие как ручка и кисть.
Иногда он также используется, когда вы хотите, чтобы две операции выполнялись вместе. Например, если вы хотите написать оператор журнала, когда вводится блок кода, и когда он выйдет, вы можете написать класс журнала, который вы можете использовать следующим образом:
using( Log log = new Log("Doing stuff") )
{
// Stuff
}
Конструктор для класса журнала может быть создан для записи сообщения, а метод Dispose также может записать его. Внесите финализатор (~ Log), чтобы подтвердить, если метод Dispose не вызван, чтобы обеспечить "использование" в "новом журнале".
Используйте using
всякий раз, когда тип реализует IDisposable
, если вы не поместите его в блок try
/catch
, тогда вы также можете (в зависимости от какой вы предпочитаете) используйте блок finally
.
Я вижу много других ответов, которые указываются, когда вы должны иметь инструкцию using
. Я хочу обратиться, когда конкретно не должен иметь оператор using
:
Если вам нужно использовать свой объект за пределами области действия текущей функции, не нужно иметь блок using
. Хорошим примером является метод factory, который возвращает соединение с базой данных или метод, который должен возвращать datareader. В любом из этих случаев, если вы создадите свой объект с помощью оператора using
, он будет удален до возврата метода и, следовательно, не будет использоваться вне метода.
Теперь вы все же хотите быть уверенным в том, что эти объекты расположены, поэтому вам все равно может понадобиться инструкция using
. Просто не включайте его в метод, где объект фактически создан. Вместо этого вы можете обернуть вызов функции в выражении using
.
Когда SomeType реализует IDisposable.
Это подсказывает разработчику, что SomeType использует неуправляемые ресурсы, которые необходимо очистить.
Пример:
using(SqlConnection MyConnection = new SqlConnection("Connection string"))
{
MyConnection.Open();
//...
// 1. SQLConnection is a type that implements IDisposable
// 2. So you can use MyConnection in a using statement
// 3. When using block finishes, it calls Dispose method of
// SqlConnection class
// 4. In this case, it will probably close the connection to
// the database and dispose MyConnection object
}
Вы можете создать свои собственные объекты, которые реализуют IDisposable:
public class MyOwnObjectThatImplementsIDisposable : IDisposable
{
//... some code
public void Dispose()
{
// Put here the code you want to be executed when the
// using statement finish.
}
}
Таким образом, вы можете использовать объект типа MyOwnObjectThanImplementsIDisposable в операторе using:
using(MyOwnObjectThatImplementsIDisposable MyObject = new MyOwnObjectThatImplementsIDisposable)
{
// When the statement finishes, it calls the
// code you´ve writed in Dispose method
// of MyOwnObjectThatImplementsIDisposable class
}
Надеюсь, что это поможет
В этом контексте оператор using
удобен для типов, реализующих IDisposable. Когда блок кода выходит из области действия оператора using
, Dispose()
называется неявным. Это хорошая привычка при работе с объектами, которые вы хотите утилизировать сразу после использования.
Один конкретный экземпляр, в котором вы должны быть осторожны с использованием блока using
, с клиентом службы WCF.
Как отмечено в этой статье MSDN, обертка WCF-клиента (который реализует IDisposable
) в блоке using
может маскировать любые ошибки, приводящие к тому, что клиент остается в неисправном состоянии (например, тайм-аут или проблема связи). Короче говоря, когда вызывается Dispose()
, запускается клиент Close()
, но бросает и ошибочно, потому что он в неисправном состоянии. Исходное исключение затем маскируется вторым исключением. Нехорошо.
Существуют различные обходные пути, в том числе один в самой статье MSDN. Другие можно найти на IServiceOriented и blog.davidbarret.net.
Я предпочитаю последний метод, сам.
Если вы хотите правило сводки. В любое время, когда объект использует IDisposable, где у вас не будет catch, используйте его. Использование, по существу, этого шаблона:
try
{
//instantiate and use object
}
finally
{
//dispose object
}
Если вам не нужна уловка, использование может спасти вас при вводе текста, что хорошо.
Возможно, стоит упомянуть, что основной причиной добавления "использования" lo С# languge является следующее: некоторые ресурсы могут быть недостаточными, чтобы не было смысла ждать, пока GC вызовет IDisposable. Например, соединения БД. Если вы используете try/catch/, наконец, вы не закончите с висящим соединением, но соединение будет оставаться висящим до тех пор, пока GC не запустится, и это может занять некоторое время (если вы не закрываете его явно). Если вы используете "использование" (извините за каламбур), вы сразу же освободите соединение, даже если забыли закрыть его и даже если какое-то исключение произошло внутри блока использования.
Другая причина, как и предыдущие сообщения, заключается в том, что программисты не всегда используют, наконец, для очистки. Если вы не используете окончательно в случае исключения, вы получите утечку ресурсов...
Одна из ситуаций заключается в том, когда вы хотите что-то сделать в начале блока кода, а затем отменить его в конце блока безоговорочно (даже если есть бросок).
Ctor для одноразового класса, который вы создаете (и вызываете внутри использования), выполнит действие, а затем метод Dispose отменит это действие. Обычно я использую его.
Основное правило: * Используйте инструкцию USING, когда объекты реализуют интерфейс IDisposable.
Этот интерфейс предоставляет метод Dispose, который должен освобождать ресурсы объекта. Если этот метод не вызывается, то объект будет оставаться в памяти до тех пор, пока CLR хочет выполнить сборку мусора. Если программист использует инструкцию USING, то в конце объект будет удален, и все ресурсы будут бесплатными.
Очень важно, чтобы все ресурсы, которые больше не использовались, были бесплатными как можно скорее.
Для получения дополнительной информации о нем просто перейдите по этой ссылке: microsoft
Другие люди уже упоминали о "IDisposable".
Но одно из предостережений при использовании выражения "using" заключается в том, любые исключения, брошенные в "использование", не будут пойманы даже мысль "SomeType" будет удаляться независимо.
Итак, в следующем фрагменте
using (SomeType t = new SomeType()){
throw new Exception("thrown within using");
}
throw new Exception("thrown within using");
не следует игнорировать.
Я бы также добавил, что используйте инструкцию using()
, если что-то реализует IDispose
, а также если это то, что вы хотите избавиться от трюков, к ресурсам NON-MANAGED, таким как соединения с базой данных и файловые дескрипторы.
Если это обычный объект с именем List<T>
, где T - это объект Customer
, который содержит имена и адреса, тогда вам не нужно. Сборщик мусора достаточно умен, чтобы управлять этим для вас. Но сборщик мусора НЕ вернет подключения к пулу подключений или закрывает дескрипторы файлов.