Вызов Dispose () против того, когда объект выходит из области видимости / метод завершается - PullRequest
14 голосов
/ 02 декабря 2009

У меня есть метод, внутри которого есть блок try/catch/finaly.В блоке try я объявляю SqlDataReader следующим образом:

SqlDataReader aReader = null;          
aReader = aCommand.ExecuteReader();

В блоке finally объекты, которые удаляются вручную, являются объектами, установленными на уровне класса.Так объекты в методе, которые реализуют IDisposable, такие как SqlDataReader выше, они автоматически удаляются?Close() вызывается на aReader после того, как цикл while выполняется для получения содержимого читателя (которое должно быть Dispose(), поскольку это вызывает Close()).Если нет вызова Close(), будет ли этот объект автоматически закрываться / удаляться по завершении метода или объект выходит из области видимости?Сценарии, которые меня смущают.

Ответы [ 6 ]

26 голосов
/ 02 декабря 2009

Нет, объекты не удаляются автоматически при выходе из области видимости.

Они даже не гарантированно удаляются, если / когда они собирают мусор, хотя многие IDisposable объекты реализуют финализатор «отступления», чтобы обеспечить их окончательную утилизацию.

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

8 голосов
/ 02 декабря 2009

Вы должны использовать блок using {...}, чтобы обернуть ваши объекты IDisposable в - метод Dispose() (который для SqlDataReader передается методу Close()) будет вызван, когда закончится использование блока. Если вы не используете using, объект будет не автоматически удаляться, когда он выходит из области видимости - он будет до финализатора объекта, если он у него есть, избавиться от ресурсов, когда он это мусор

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // ... do stuff
}   // aReader.Dispose() called here
1 голос
/ 02 декабря 2009

Я согласен со всем вышеперечисленным. Вы должны убедиться, что вы вызываете Dispose() самостоятельно, и самый простой способ сделать это с помощью оператора using (вы также можете сделать это самостоятельно в блоке finally - это более многословно, но иногда необходимо). Если вы этого не сделаете, ваше приложение может обнаружить утечку неуправляемых ресурсов, таких как дескрипторы, или даже неуправляемую память, особенно если где-то под всем этим используются некоторые COM-компоненты или выполняются вызовы в Win32 API. Это может привести к проблемам с производительностью и стабильностью, а также к чрезмерному использованию ресурсов.

Тот факт, что объекты, реализующие IDisposable, "должны" реализовывать финализатор, который вызывает их метод Dispose(bool disposing) для освобождения неуправляемых ресурсов, не гарантирует, что это произойдет, поэтому вам определенно не следует полагаться на него. См., Например, http://msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspx для получения дополнительной информации по этому вопросу.

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

1 голос
/ 02 декабря 2009

Шаблон Dispose не дает никаких гарантий относительно того, какие объекты будут вызывать Dispose для каких других объектов; иногда это может случиться, но вам все равно. Вместо этого вы обязаны убедиться, что Dispose () вызывается для всех объектов IDisposable. Лучший способ сделать это с помощью оператора using. Например:

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // your code
}
0 голосов
/ 02 декабря 2009

Я озадачен утверждением «В блоке finally объекты, которые удаляются вручную, - это объекты, заданные на уровне класса». Под объектами, установленными на уровне класса, вы подразумеваете поля? Вы, вероятно, не должны избавляться от них в обычном методе, потому что тогда срок жизни полей непредсказуем и зависит от того, какие методы вы вызвали. Было бы лучше реализовать IDisposable и избавиться от полей в вашем методе Dispose.

0 голосов
/ 02 декабря 2009
...