Подтвердить что ты не робот

Вызов Dispose() vs, когда объект выходит за пределы области/метода

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

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

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

РЕДАКТИРОВАТЬ: я знаю об using но есть сценарии, которые меня смущают.

4b9b3361

Ответ 1

Нет, объекты не будут автоматически удалены, когда они выйдут из области видимости.

Их даже не гарантируют, что они будут удалены, если/когда они будут собраны в мусор, хотя многие объекты IDisposable реализуют "резервный" финализатор, чтобы гарантировать, что они в конечном итоге будут удалены.

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

Ответ 2

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

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // ... do stuff
}   // aReader.Dispose() called here

Ответ 3

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

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // your code
}

Ответ 4

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

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

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

Ответ 5

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