2009-03-10 2 views
9

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

+0

Простите, Марк, но вы лаете неправильное дерево, возможно, в неправильном лесу. Посмотрите на ссылки в других ответах, если вы мне не верите. –

+1

Вау - почему кто-то проголосует за закрытие? Это отличная дискуссия! –

+0

Мне нужно будет вернуть мое предыдущее утверждение: MS говорит, что пара Dispose/Finalize - это нормально. Лично мне не нравится этот подход по причинам, изложенным ниже, но ktrauberman нашел ссылку, которая доказывает, что я не должен быть настолько неуступчивым в этом вопросе ... поэтому я уступаю. –

ответ

11

Если вы правильно реализуете IDisposable, вы также должны включить финализатор, который будет вызывать Dispose() на вашем объекте.

Если вы это сделаете, он будет вызван GC. Тем не менее, все еще ОЧЕНЬ хорошая идея, чтобы попытаться всегда распоряжаться этими объектами самостоятельно.

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

+0

Извините, Марк, но сборка мусора C# - это не волшебная палочка, которую вы подразумеваете. Если объект реализует IDispose, вы должны утилизировать его явно, предпочтительно с помощью. Однако ваши советы подходят для других объектов, но ресурсы, не связанные с памятью, опасны! –

+0

Если пользователь никогда не вызывает Dispose(), и они не используют блок использования, любые неуправляемые ресурсы никогда не будут очищены. Здесь это зависит от того, почему ваш класс реализует IDiposable, но в вопросе явно указано «освободить неуправляемые ресурсы». Именно по этой причине существуют финализаторы. –

+0

Я не уверен, что мы не согласны с Понтом; Я создаю классы IDisposable специально для использования в блоке Using. Если нет, вам действительно нужно будет называть это явно, чтобы освободить неуправляемые ресурсы, освободить соединения и т. Д. –

2

Dispose() вызывается в конце блока использования, так что вы можете рассчитывать на действия Dispose (например, закрытие соединения db), которые должны выполняться по мере того, как объект выходит из области видимости. Просто как тот.

Обновление: нет ничего конкретного для неуправляемых ресурсов в вызове Dispose (хотя это распространенное использование).

Обновление 2: есть немного дискуссии по теме, которую начал Рид Копси, полезной для понимания IDisposable. Я очень рекомендую this article людям, желающим узнать больше.

В двух словах класс IDisposable позволяет явно обрабатывать освобождение ресурсов (обычно неуправляемых ресурсов или соединений с базой данных) с помощью метода Dispose(). Идентифицируемые экземпляры классов должны быть созданы в блоке «Использование», чтобы гарантировать, что метод Dispose фактически вызывается. Если вы этого не сделаете (или явно вызывать его в блоке «finally» и т. Д.), То ваш метод Dispose не будет вызываться, и вы будете сиротом объектов, которые хотите очистить. В все случаях, I место Одноразовые классы в разделе Использование блоков, и вы тоже должны.

В качестве альтернативы вы можете обрабатывать очистку ресурсов в Finalizer (класс Destructor). Это будет вызываться автоматически, когда класс GC'd. Недостатки этого подхода заключаются в том, что вы не будете явно контролировать , когда объекты очищаются, и есть некоторые проблемы с потоками, с которыми можно бороться. Таким образом, например, проблемы в Destructors очень сложно отлаживать из-за того, что они называются асинхронно и в другом потоке. Единственное преимущество заключается в том, что вам не нужно забывать называть ваш деструктор, как вы делаете Dispose. Конечно, если вы всегда используете использование блоков, это не проблема.

ПРИМЕЧАНИЕ: Я ktrauberman, Рид и Понтус сделали несколько хороших моментов о том, как вы можете обойти пункты, которые я делаю ниже. Это то, что я делаю, но я не могу утверждать, что это единственный способ сделать что-то. В самом деле, Microsoft даже рекомендует вызывать Dispose() из вашего Finalizer в некоторых случаях. Тем не менее, я оставлю обсуждение здесь, как иллюстрация того, почему важно следовать рекомендациям Рида: будьте осторожны при смешивании Destructors и Dispose().

Где я не согласен с ответом Рида в утверждении, что вы должны реализовать класс IDisposable, вызвав Dispose() в своем Finalizer. Это просто объединяет две различные конструкции и может привести к проблемам. Например, если вы создаете экземпляр класса IDisposable в блоке использования и, вы вызываете Dispose() в Destructor, он будет вызываться дважды - с потенциально неприятными и трудными для отладки сбоев (опять же - вы не контролируете время ГХ). (Примечание стороны: это на самом деле так деструкторы в целом - они могут, при определенных обстоятельствах можно назвать более чем один раз!)

+0

Mark, Статья, на которую вы ссылаетесь, противоречит вашей позиции. Он говорит на стр. 3 «Корпорация Майкрософт рекомендует выполнять как Dispose, так и Finalize при работе с неуправляемыми ресурсами». На стр. 4 также показан пример, где он вызывает Dispose() из деструктора. –

+0

Я не думаю, что вы полностью понимаете, что делает GC.SupressFinalize(). Вы вызываете это в конце вашего метода Dispose(), поэтому, если разработчик вызывает Dispose(), сборщик мусора никогда не запускает финализатор, поэтому очистка происходит только один раз. –

+0

kt - спасибо за дебаты. Я не смешиваю их, но, как я сказал выше, я должен признать вашу точку зрения и сделать это с радостью. Дискуссии о SO всегда хороши для того, чтобы подтолкнуть конверт того, что мы знаем. –

2

Dispose вызывается в нескольких местах:

  1. В конце использования блок.
  2. Когда явно вызвано (например, в try {} finally {}.)

Рекомендуется использовать его самостоятельно, когда вы закончите с ресурсом, чтобы лучше управлять ресурсами.

EDIT: Я ошибся. Dispose НЕ вызывается во время сбора мусора. См. Статью this.

+0

Dispose() не вызывается автоматически во время сбора мусора. –

+0

+1 для комментария Брайана. –

+0

Просто отредактирован. Я провел некоторое исследование после публикации (что я должен был сделать заранее), мой плохой. –

2

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

Как вы говорите, это автоматически называется и конец блока using.

Смежные вопросы