Сколько работы в методе Dispose? - PullRequest
3 голосов
/ 20 января 2012

Сколько работы нужно выполнить в методе Dispose? В конструкторах я всегда придерживался позиции, что вы должны делать только то, что абсолютно необходимо для создания экземпляра объекта. В этом случае я также всегда придерживался подхода, согласно которому вы должны очищать открытые ресурсы ТОЛЬКО при утилизации. Закрытие файлов, освобождение памяти, удаление одноразовых дочерних объектов и т. Д. Не следует выполнять длительные процессы, такие как касание файлов, доступ к базам данных и т. Д. В методе Dispose.

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

Ответы [ 5 ]

4 голосов
/ 20 января 2012

Я не прав?

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

Но это сложно обобщить. В некоторых случаях метод Dispose просто используется для обеспечения выполнения какой-либо операции. Например, в ASP.NET MVC есть вспомогательный Html.BeginForm, который используется следующим образом:

using (Html.BeginForm())
{

}

и все, что делает метод Dispose, это отображает закрывающий тег </form>. Таким образом, как вы можете видеть, люди могут проявлять творческий подход к шаблону, и очень трудно делать выводы без определенного сценария.

Но в наиболее распространенных ситуациях он используется для освобождения неуправляемых ресурсов.

2 голосов
/ 20 января 2012

«Это зависит». О каком доступе к базе / файлу мы говорим? Скажем, например, что ваш одноразовый предмет - это своего рода регистратор, и вы используете его по следующей схеме

using(Logger logger = new Logger())
{
    foo.PerformTask();
}

Я думаю, что для логгера было бы вполне приемлемо написать «Журнал запущен» в конструкторе «Журнал завершен» в Dispose.

1 голос
/ 20 января 2012

Сколько работы нужно выполнить в методе Dispose?

Это зависит от того, реализуете ли вы интерфейс IDispose только для удобства использования оператора, или вы реализуете полный шаблон IDisposable? В последнем случае полного одноразового шаблона все еще допустимо выполнять более сложные действия при условии, что вы «утилизируете» параметр true (т.е. вы не в GC).

Когда вы определяете финализатор, который вызывает метод Dispose, на самом деле беспокоиться не о чем. Подобные случаи использования / злоупотребления интерфейсом IDisposable, о котором упоминалось, уже были другими (т.е. using (Html.BeginForm())) способны выполнять любые действия. Зачастую это может значительно снизить сложность кода и предотвратить случайное забвение кодировщиками некоторых закрывающих действий. Один недостаток (или недостаток) заключается в том, что код выполняется немного по-другому внутри блока finally .

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

Объекты, ИМХО, должны быть действительны после постройки. Так что если у вас есть много работы, чтобы сделать что-то, пусть будет так. Не думайте о рабочей нагрузке, думайте о потребителе вашего объекта и его удобстве использования. Методы Initialize () после построения suck;)

В этом случае я также всегда придерживался подхода, согласно которому вы должны ТОЛЬКО убирать открытые ресурсы при утилизации. Закрытие файлов, освобождение памяти, удаление одноразовых дочерних объектов и т. Д. Не следует выполнять длительные процессы, такие как касание файлов, доступ к базам данных и т. Д. В методе Dispose.

На самом деле давайте немного разберемся с этим ...

Удаление из вызова GC для финализатора

Когда вы реализуете шаблон IDisposable (не интерфейс, шаблон, финализатор и все), вы, по сути, говорите, что у вашего объекта есть неуправляемый ресурс, о котором никто больше не знает. Это означает, что вы вызвали вызов CreateFile в Win32, или, может быть, вы назвали Marshal.AllocHGlobal или что-то в этом роде. По сути, у вас, скорее всего, есть член экземпляра IntPtr, с которым нужно что-то делать, чтобы предотвратить утечку памяти. Это ЕДИНСТВЕННЫЕ типы действий, которые должны быть выполнены, когда параметр распоряжения имеет значение false (то есть вызывается из финализатора в потоке GC).

Как правило, вы НЕ вызываете метод Dispose для детей. Вы не должны ожидать, что любой дочерний объект будет действительным. Простое прикосновение к члену дочернего объекта может случайно «оживить» или воскресить его .

Поэтому, когда вы пишете код, который выполняется в методе Dispose, вызываемом из Finalizer, вы должны быть осторожны. Вы выполняете в потоке GC, пока остальная часть вашего приложения ждет вас. Вы должны выполнить как можно меньше операций, чтобы освободить неуправляемую память / ресурс и выйти. Никогда не создавайте исключение, и если вы вызываете API, который может выдать, вы должны перехватить любое возникшее исключение. Распространение исключений обратно в GC приведет к преждевременному прерыванию потока финализатора, и оставшиеся объекты, которые должны быть завершены, не смогут очиститься.

Удаление из метода IDisposable.Dispose ()

Как я уже говорил, использование метода Dispose является достаточно безопасным и может безопасно вместить любое количество кода / процесса. Здесь вы можете освободить неуправляемые ресурсы, вызвать метод dispose дочерних объектов, очистить и закрыть файлы и т. Д. Большинство написанных мной методов Dispose не имеют связанного Finalizer и, следовательно, не следуют шаблону IDisposable, однако они реализовать IDisposable только для удобства оператора using.

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

Вы абсолютно правы, когда рассматриваемый метод dispose используется из финализатора.Ваши утверждения о том, что вы должны и чего не должны делать в методе Dispose, должны быть перефразированы для применения ко всему, что вызывается финализатором.Тот факт, что это обычно делается в методе, называемом Dispose, является условием, шаблоном IDisposable, но эти проблемы могут легко существовать в других методах, используемых Finalizer.

0 голосов
/ 20 января 2012

Вы должны склоняться к заключению, к которому вы уже пришли. Однако существуют ситуации, когда вам необходимо убедиться, что службы остановлены, и это может включать такие вещи, как сообщения, регистрируемые для завершения работы службы, или сохранение текущего состояния времени выполнения в хранилище данных. Этот тип удаления обычно применяется только к вещам, которые имеют жизненный стиль приложения, то есть они существуют все время, пока приложение работает. Так что есть ситуации за пределами ожидаемой нормы. Как и в случае с каждым правилом , которому вы должны следовать при написании кода.

0 голосов
/ 20 января 2012

Если объект делает что-то с состоянием некоторых внешних сущностей таким образом, что делает их более полезными для этого, но менее полезными для всех остальных, метод Dispose объекта должен делать все необходимое для восстановления вне этих сущностей. в более общее полезное состояние. Если кто-то хочет, чтобы объект не выполнял слишком много работы в Dispose, он должен спроектировать объект так, чтобы никогда не оставлять какие-либо внешние объекты в состоянии, которое было бы обременительным для очистки.

Кстати, Microsoft любит использовать термин «неуправляемые ресурсы» и приводит примеры, но никогда не предлагает хорошего определения. Я хотел бы предложить, чтобы объект содержал «неуправляемый ресурс», если внешняя сущность изменяет свое поведение от имени этого объекта способом, который наносит ущерб другим объектам или сущностям, и если эта внешняя сущность будет продолжать изменять свое поведение до объект мешает ему сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...