Некоторые сложные вопросы по использованию оператора - PullRequest
2 голосов
/ 20 марта 2009

Я знаю, что здесь есть несколько потоков о том, как использовать оператор using и вызвать метод Dispose (). Я прочитал большинство из этих тем.

Если я вызываю Dispose (), вызывает ли он Close ()?

Если я хочу использовать объект (скажем, SqlDataReader), но затем использовать его снова в другом блоке кода, не должен ли я вызвать Dispose ()? Что также означает опускание оператора using.

Также, чтобы уточнить, если FileStream оборачивает StreamWriter и я вызываю dispose для FileStream, это вызовет Flush (), Close () и Dispose () (в зависимости от того, вызывает ли Dispose () Close ()) в StreamWriter, верно? Аналогично, если я вызову Close для FileStream, это вызовет только Flush () и Close () для FileStream.

Является ли проверка IL хорошим способом ответить на эти вопросы о том, что происходит под капотом?

Ответы [ 8 ]

6 голосов
/ 20 марта 2009

«Если я вызываю Dispose (), вызывает ли он Close ()?»

По идее, так и должно быть. Все классы BCL делают это, но автор библиотеки должен правильно обработать это. Если используемая библиотека выполнена правильно, Dispose () также должен закрыть () [и Close () будет Dispose () - вызовы должны быть взаимозаменяемыми].

"Если я хочу использовать объект (скажем, SqlDataReader), но затем использовать его снова в другом блоке кода, не должен ли я вызвать Dispose ()? Что также означает, что оператор using пропускается."

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

"Также, чтобы уточнить, если FileStream оборачивает StreamWriter и я вызываю dispose для FileStream, это вызовет Flush (), Close () и Dispose () (в зависимости от того, вызывает ли Dispose () метод Close ()) в StreamWriter, верно? Аналогично, если я вызову Close для FileStream, это вызовет только Flush () и Close () для FileStream. "

Если вы оборачиваете FileStream вокруг StreamWriter, я настоятельно рекомендую обращаться с ними последовательно. Используйте один оператор using с обоими членами, чтобы они оба удалялись в конце блока. Это самый безопасный, самый чистый подход.

«Является ли проверка IL хорошим способом ответить на эти вопросы о том, что происходит под капотом?»

Это путь, хотя и более сложный. Читайте в MSDN об использовании и потоках, и документация объяснит это в более простых терминах, чем попытка разобрать IL. ИЛ скажет вам ТОЧНО, что произойдет, если вам интересно.

3 голосов
/ 20 марта 2009

Если я вызываю Dispose (), вызывает ли она Close ()?

Close () и Dispose () делают то же самое, если реализованы правильно; это просто наименование. Звучит проще закрыть файл, чем утилизировать его. См. Реализация финализации и удаления для очистки неуправляемых ресурсов esspecialy 'Настройка имени метода удаления'.

Если я хочу использовать объект (скажем, SqlDataReader), но затем использовать его снова в другом коде # блок, я не должен вызывать Dispose ()? Что также означает опускание оператора using.

Да, поскольку объект удаляется при выходе из блока использования.

Кроме того, чтобы уточнить, если FileStream оборачивает StreamWriter, и я вызываю dispose для> FileStream, это вызовет Flush (), Close () и Dispose () (в зависимости от того, является ли Dispos () вызывает Close ()) на StreamWriter, верно? Аналогично, если я вызову Close для FileStream,> это вызовет только Flush () и Close () для FileStream.

Это другой путь; StreamWriter основан на базовом потоке, а закрытие StreamWriter закрывает базовый поток, который может быть FileStream; см. MSDN для справки. Следовательно, достаточно одного оператора использования для StreamWriter.

1 голос
/ 20 марта 2009

Dispose - основной метод, связанный с интерфейсом IDisposable и шаблоном Disposable.

Microsoft вызывает метод наподобие Close () a Псевдоним, специфичный для домена , и это дает идею. Но это все еще зависит от Реализатора Класса, могут быть различия, такие как возможность открыть или нет. Но в целом вам не нужно (должно быть) заботиться.

sqlDataReader - плохой пример, потому что вы не можете использовать его повторно. И в целом это лучший совет для всех других одноразовых предметов.

1 голос
/ 20 марта 2009

Если я вызываю Dispose (), вызывает ли он Close ()?

Не обязательно. Иногда я использую Reflector, чтобы проверить, что на самом деле происходит в Close and Dispose.

Если я хочу использовать (...) снова в другом блоке кода, не должен ли я вызвать Dispose ()?

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

Как вы сказали, для этого есть много ресурсов, но я приведу ссылку на MSDN для некоторых рекомендаций: Реализация финализации и удаление для очистки неуправляемых ресурсов .

1 голос
/ 20 марта 2009

Если я вызываю Dispose (), вызывает ли она Close ()?

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

Если я хочу использовать объект (скажем, SqlDataReader), но затем использовать его снова в другом блоке кода, не должен ли я вызвать Dispose ()? Что также означает опускание оператора using.

Если вы хотите снова использовать объект, вам определенно не следует его утилизировать. Однако, как правило, вы должны использовать два отдельных соединения, если вы идете в базу данных два разных раза. Как правило, не рекомендуется хранить IDataReader дольше, чем необходимо для получения необходимых данных.

Также, чтобы уточнить, если FileStream оборачивает StreamWriter и я вызываю dispose для FileStream, это вызовет Flush (), Close () и Dispose () (в зависимости от того, вызывает ли Dispose () Close ()) в StreamWriter, верно? Аналогично, если я вызову Close для FileStream, это вызовет только Flush () и Close () для FileStream.

Удаление объекта, который оборачивает другой одноразовый объект, должно вызвать Dispose на внутреннем объекте. Вызов Close для FileStream вызовет его метод Dispose для товара, поэтому он также будет действовать в обоих потоках.

Является ли проверка IL хорошим способом ответить на эти вопросы о том, что происходит под капотом?

Проверка IL определенно ответит на большинство из этих вопросов. Как говорит @ Rich , вы также можете просто попробовать отладить свои собственные реализации Dispose. Конечно, есть также документация MSDN, с которой нужно начать, прежде чем пытаться разобраться с этим, и Reflector, если вы не хотите обойтись в IL.

0 голосов
/ 20 марта 2009

Я пытаюсь переместить предложение using выше, поскольку я предпочитаю использовать этот синтаксис. Затем вызовите другие блоки, используя этот ресурс изнутри этого ресурса, используя блок.

0 голосов
/ 20 марта 2009

Нет, IDisposable не требует Close (), но объект, реализующий IDispose, может быть достаточно хорош для включения его в метод Dispose ().

Вы должны утилизировать его, как только получите данные, которые вы получаете из БД. Не оставляйте читателя открытым дольше, чем вам нужно. Если вы выполняете какую-либо настоящую работу с данными, используйте dataAdapter / dataset вместо reader.

Нет идей. Проверьте сгенерированный IL

0 голосов
/ 20 марта 2009

Более простой способ отладки этого, чем прохождение кода IL, состоит в том, чтобы извлечь из вашего IDisposable, переопределить необходимые методы, ничего не делая, кроме вызова base.[Method Name](), и установить точку останова в каждом из них. Затем, если вы оберните свой производный класс в блок using, вы увидите жизненный цикл этих вызовов.

...