Прочитав потоки Является ли SqlCommand.Dispose достаточно? и Закрытие и удаление службы WCF. Я задаваясь вопросом о таких классах, как SqlConnection или один из нескольких классов, наследующих класс Stream, имеет значение, если я закрываю Dispose, а не Close?
Закрыть и удалить - что звонить?
Ответ 1
Я хочу прояснить эту ситуацию.
В соответствии с рекомендациями Microsoft рекомендуется использовать метод Close
, где это целесообразно. Вот цитата из Рекомендации по разработке рамок
Рассмотрим метод предоставления
Close()
, в дополнение кDispose()
, если close - стандартная терминология в области. При этом важно, чтобы реализацияClose
идентичнаDispose
...
В большинстве случаев методы Close
и Dispose
эквивалентны. Основное отличие между Close
и Dispose
в случае SqlConnectionObject
:
Приложение может вызывать
Close
больше чем один раз. Исключением не является генерируется.Если вы вызвали метод
Dispose
SqlConnection
Состояние объекта будет reset. Если вы попытаетесь позвонить любому метод на размещенномSqlConnection
объект, вы получите исключение.
Это сказало:
- Если вы используете объект подключения один
время, используйте
Dispose
. - Если объект подключения должен быть повторно использован,
используйте метод
Close
.
Ответ 2
Как обычно, ответ: это зависит. Различные классы реализуют IDisposable
по-разному, и вам решать необходимые исследования.
Что касается SqlClient
, рекомендуется использовать следующее:
using (SqlConnection conn = /* Create new instance using your favorite method */)
{
conn.Open();
using (SqlCommand command = /* Create new instance using your favorite method */)
{
// Do work
}
conn.Close(); // Optional
}
Вы должны звонить Dispose
(или Close
*) в соединении! Do not ждут, когда сборщик мусора очистит ваше соединение, это свяжет соединения в пуле до следующего цикла GC (по крайней мере). Если вы вызываете Dispose
, нет необходимости вызывать Close
, а так как конструкция using
позволяет легко обрабатывать Dispose
правильно, нет причин для вызова Close
.
Соединения автоматически объединяются, а вызов Dispose
/Close
в соединении физически не закрывает соединение (при нормальных обстоятельствах). Не пытайтесь реализовать свой собственный пул. SqlClient
выполняет очистку соединения при извлечении из пула (например, восстановление контекста базы данных и параметров подключения).
*, если вы вызываете Close
, обязательно сделайте это безопасным способом (т.е. в блоке catch или finally).
Ответ 3
Вам нужно вызвать Dispose()!
Dispose() предназначен для вызова разработчика, сборщик мусора вызывает Finalize(). Если вы не вызываете Dispose() на своих объектах, любые неуправляемые ресурсы, которые они используют, не будут удаляться до тех пор, пока сборщик мусора не появится и вызовет окончательный вариант (и кто знает, когда это произойдет).
Этот сценарий называется не детерминированным завершением и является общей ловушкой для разработчиков .net. Если вы работаете с объектами, реализующими IDisposable, тогда вызовите Dispose() на них!
http://www.ondotnet.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html?page=last
Хотя может быть много экземпляров (например, на SqlConnection), на которых вы вызываете Disponse() на какой-либо объект, и он просто вызывает Close() на нем или закрывает дескриптор файла, он всегда всегда лучше всего подходит для вызова Dispose()! если вы не планируете повторно использовать объект в самом ближайшем будущем.
Ответ 4
Для SqlConnection
, с точки зрения самого соединения, они эквивалентны. Согласно Reflector, Dispose()
вызывает Close()
, а также выполняет несколько дополнительных операций освобождения памяти - в основном путем установки членов, равных нулю.
Для Stream они фактически эквивалентны. Stream.Dispose()
просто вызывает Close().
Ответ 5
Этот быстрый совет стал длинным ответом. К сожалению.
Как сказал тиллер в своем приятном ответе, вызов Dispose()
- отличная практика программирования. Это связано с тем, что этот метод должен "объединить" все необходимые ресурсы, чтобы не было ненужных открытых ресурсов. Например, если вы написали некоторый текст в файл и не смогли закрыть файл (освободите ресурс), он останется открытым, и никто другой не сможет его написать до тех пор, пока GC не появится и не сделает то, что вам нужно сделал.
Теперь в некоторых случаях будут "финализировать" методы, более специфичные для класса, с которым вы имеете дело, например StreamWriter.Close()
, который переопределяет TextWriter.Close()
. Действительно, они обычно более подходят для ситуации: StreamWriter Close()
, например, очищает поток и базовый кодер до Dispose()
объекта! Круто!
Однако, просматривая MSDN, вы обнаружите, что даже Microsoft иногда путают множество дозаторов и утилизаторов. На этой веб-странице, например, в некоторых примерах Close()
вызывается перед неявным Dispose()
(см. используя инструкцию, если вы не понимаете, почему это неявно), и в одном из них в частности, они не утруждают себя. Почему это так? Я тоже был озадачен.
Я понял (и, подчеркиваю, это оригинальное исследование и я конечно, может потерять репутацию, если я ошибаюсь) заключается в том, что Close()
может завершиться ошибкой, давая исключение, оставив ресурсы открытыми, а Dispose()
, несомненно, освободит их. Вот почему a Dispose()
должен всегда защищать вызов Close()
(извините за каламбур).
MyResource r = new MyResource();
try {
r.Write(new Whatever());
r.Close()
finally {
r.Dispose();
}
И да, я думаю, Microsoft поскользнулась на этом примере. Возможно, эта метка никогда не будет очищена от файла.
Завтра я исправляю свой старый код.
Изменить: извините Брэннон, я не могу прокомментировать ваш ответ, но вы уверены, что было бы неплохо позвонить Close()
в блок finally
? Я предполагаю, что исключение из этого может испортить остальную часть блока, что, вероятно, будет содержать важный код очистки.
Ответ Brannon's: отлично, просто не забудьте вызвать Close()
, когда это действительно необходимо (например, при работе с потоками - мало что знают о SQL-соединениях в .NET).
Ответ 6
Typecast для iDisposable и вызов на него. Это вызовет любой метод, настроенный как реализация "iDisposable.Dispose", независимо от того, что называется функцией.
Ответ 7
Обычно мы сталкиваемся с проблемой в Close(), Abort() и Dispose(), но позвольте мне сказать вам разницу между ними.
1) ABORT: - Я не буду предлагать использовать это, потому что, когда вызывается прерывание, клиент удалит соединение, не сообщив серверу, что сервер будет ждать некоторое время (приблизительно 1 мин). Если у вас есть массовый запрос, вы не можете использовать abort(), потому что это может привести к тайм-ауту для вашего ограниченного пула соединений.
2) Закрыть: - Закрыть очень хороший способ закрыть соединение, потому что при закрытии соединения он вызывает сервер и подтверждает, что сервер тоже закрывается этой стороной.
Вот еще одна вещь, чтобы посмотреть. В некоторых случаях, если возникает ошибка, тогда это не очень хороший способ написать код, в конце концов, что connection.close(), потому что в это время будет вызвано состояние связи.
3) Утилизируйте: - Это один из близких, но после закрытия соединения вы не можете его снова открыть.
Итак, попробуйте этот путь,
private void CloseConnection(Client client)
{
if (client != null && client.State == CommunicationState.Opened)
{
client.Close();
}
else
{
client.Abort();
}
}