Закрыть и утилизировать - куда звонить?

После прочтения темы Достаточно ли SqlCommand.Dispose? и закрытие и удаление службы WCF Мне интересно, для классов, таких как SqlConnection или одного из нескольких классов, унаследованных от класса Stream, имеет ли значение, если я закрываю Dispose, а не Close?

8 ответов

Решение

Я хочу прояснить эту ситуацию.

Согласно рекомендациям Microsoft, это хорошая практика Close метод, где это подходит. Вот цитата из руководящих принципов проектирования Framework

Рассмотрите возможность предоставления метода Close(), в добавок к Dispose(), если близко - стандартная терминология в области. При этом важно, чтобы вы сделали Close реализация идентична Dispose...

В большинстве случаев Close а также Dispose методы эквивалентны. Основное различие между Close а также Dispose в случае SqlConnectionObject является:

Приложение может позвонить Close более одного раза. Никаких исключений не генерируется.

Если вы позвонили Dispose метод SqlConnection состояние объекта будет сброшено. Если вы попытаетесь вызвать любой метод по утилизации SqlConnection объект, вы получите исключение.

Это говорит:

  • Если вы используете объект подключения один раз, используйте Dispose ,
  • Если объект подключения необходимо использовать повторно, используйте Close метод.

Как обычно, ответ: это зависит. Различные классы реализуют 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 *) на связи! Не ждите, пока сборщик мусора очистит ваше соединение, это будет связывать соединения в пуле до следующего цикла GC (по крайней мере). Если вы позвоните Dispose, не надо звонить Close и так как using конструкция делает его таким простым в обращении Dispose правильно, действительно нет причин звонить Close,

Соединения автоматически объединяются, и вызов Dispose / Close при соединении физически не закрывает соединение (при нормальных обстоятельствах). Не пытайтесь реализовать свой собственный пул. SqlClient выполняет очистку соединения при его извлечении из пула (например, восстановление контекста базы данных и параметров соединения).

* если вы звоните Close, убедитесь, что вы делаете это безопасным для исключений способом (т.е. в блоке catch или finally).

За SqlConnectionс точки зрения самого соединения они эквивалентны. По словам Отражателя, Dispose() звонки Close() а также делает несколько дополнительных операций по освобождению памяти - в основном, устанавливая члены равными нулю.

Для Stream они фактически эквивалентны. Stream.Dispose() просто вызывает Close().

Вам необходимо вызвать 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()! если вы не планируете повторно использовать объект в самом ближайшем будущем.

Этот быстрый совет стал длинным ответом. Сожалею.

Как отметил Тайлер в своем приятном ответе, Dispose() отличная практика программирования Это связано с тем, что этот метод должен объединять все необходимое освобождение ресурсов, чтобы не было ненужных открытых ресурсов. Например, если вы записали какой-то текст в файл и не смогли закрыть файл (освободить ресурс), он останется открытым, и никто больше не сможет писать в него, пока GC не придет и не сделает то, что вы должны иметь. сделанный.

Теперь, в некоторых случаях будут "финализировать" методы, более специфичные для класса, с которым вы имеете дело, например, StreamWriter.Close(), который переопределяет TextWriter.Close(), Действительно, они обычно больше подходят для ситуации: StreamWriter Close() например, очищает поток и базовый кодер перед Dispose() Инг объект! Здорово!

Однако, просматривая MSDN, вы обнаружите, что даже Microsoft иногда сбивает с толку множество приближенных и распорядителей. На этой веб-странице, например, в некоторых примерах Close() называется перед неявным Dispose() (см. использование оператора, если вы не понимаете, почему оно неявное), и в частности, они не беспокоятся. С чего бы это? Я тоже был озадачен.

Причина, по которой я понял (и, подчеркиваю, это оригинальное исследование, и я, безусловно, могу потерять репутацию, если я ошибаюсь), заключается в том, что Close() может дать сбой, приводя к исключению, оставляя ресурсы открытыми, в то время как Dispose() наверняка освободит их. Вот почему Dispose() всегда должен охранять Close() позвонить (извините за каламбур).

MyResource r = new MyResource();

try {
  r.Write(new Whatever());

  r.Close()
finally {
  r.Dispose();
}

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

Завтра я исправляю свой старый код.

Редактировать: извините Браннон, я не могу комментировать ваш ответ, но вы уверены, что это хорошая идея, чтобы позвонить Close() на finally блок? Я предполагаю, что исключение из этого может разрушить остальную часть блока, который, вероятно, будет содержать важный код очистки.

Ответ Браннона: отлично, просто не забудь позвонить Close() когда это действительно необходимо (например, когда имеешь дело с потоками - мало что знаешь о соединениях SQL в.NET).

Наберите iDisposable, и вызовите распоряжение об этом. Это вызовет любой метод, сконфигурированный как реализующий "iDisposable.Dispose", независимо от того, как названа функция.

Обычно мы сталкиваемся с проблемой в Close(), Abort() и Dispose(), но позвольте мне рассказать вам разницу между ними.

1) ABORT:- Я не буду предлагать использовать это, потому что, когда вызывается abort, клиент удаляет соединение, не сообщая серверу, поэтому сервер будет ждать некоторое время (приблизительно 1 мин). Если у вас массовый запрос, то вы не можете использовать abort(), поскольку это может привести к превышению времени ожидания для вашего ограниченного пула соединений.

2) Закрыть:- Закрыть - это очень хороший способ закрыть соединение, потому что при закрытии соединения он вызовет сервер и подтвердит, что сервер тоже закрывается.

Здесь еще одна вещь, чтобы посмотреть. В некоторых случаях, если генерируется ошибка, тогда это не очень хороший способ написать код, наконец, в connection.close(), потому что в это время будет нарушено состояние связи.

3) Утилизировать:- это один из типов закрытия, но после закрытия соединения вы не сможете открыть его снова.

Попробуй так,

private void CloseConnection(Client client)
    {
        if (client != null && client.State == CommunicationState.Opened)
        {
            client.Close();
        }
        else
        {
            client.Abort();
        }
    }

У меня только что возникла проблема с приложением net6, использующимTransactionScope: у меня было несколько последовательно созданных, открытых и удаленных соединений, но я ловилThis platform does not support distributed transactionsпри завершении объема (при этом явно не было распределенных транзакций).

Проблема была решена путем добавления вызова метода. Большинство ответов говорят об этом и идентичны, но, похоже, это не так: из того, что я почерпнул из исходного кода,Closeметод явно возвращает подключение к пулу, в то время как идентичный код дляDispose.

Другие вопросы по тегам