Для чего именно нужен IDisposable?
Возможный дубликат:
Правильное использование интерфейса IDisposable
Я пытался найти реальный ответ на мой вопрос в книгах, Интернете и в stackru, но пока что ничто не помогло мне, так что, надеюсь, я смогу сформулировать свою проблему достаточно точно, чтобы иметь смысл.
В общем, я всегда находил одно и то же базовое использование, как освободить память, что составляет ок. следующим образом, и я понимаю сам код:
public class MyClass : IDisposable
{
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Dispose(true);
GC.SuppressFinalize(this);
disposed = true;
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//free managed ressources
}
// free other ressources
}
~MyClass()
{
Dispose(false);
}
}
Это имеет полное значение, как методы работают. Но теперь мой вопрос: зачем нам базовый класс IDisposable? В этом примере кода мы определяем метод Dispose()
, Как я читал везде, этот метод является частью IDisposable, но мы только что определили этот метод в MyClass
и этот код все еще будет работать, если мы не реализуем базовый класс IDisposable, или я ошибаюсь с этим предположением?
Я не совсем новичок в C#, но мне еще предстоит многому научиться, так что, надеюсь, кто-то может привести меня в правильном направлении. Я проверил другой пост с тем же вопросом, но не смог его найти, поэтому, если он существует и отвечает на мой вопрос, пожалуйста, ведите меня туда, и я удалю этот пост.
4 ответа
Вы правы, как ваш деструктор ~MyClass
вызов Dispose
Вроде нет необходимости в интерфейсе IDisposable
,
Но Dispose
не вызывается только деструктором. Вы можете назвать это сами в коде, если хотите, чтобы неуправляемые ресурсы были удалены. Это необходимо, потому что вы не знаете, когда вызывается деструктор (это зависит от сборщика мусора).
В заключение, IDisposable.Dispose
вызывается, когда вы используете using
,
using(MyDisposableClass myObject = new MyDisposableClass())
{
// My Code
}
эквивалентно:
MyDisposableClass myObject = new MyDisposableClass();
try
{
// My Code
}
finally
{
myObject.Dispose();
}
Реализация IDispose дает вам место для освобождения ресурсов, которые вы "держите", таких как потоки, дескрипторы или соединения с базой данных.
Dispose() вызывается из сборщика мусора, в основном спрашивая объект: "если есть что-то, что вам больше не нужно, но я не могу понять; выпустить это сейчас; очистить!"
В некотором смысле сравнимо с деструктором, например, в C++
Разница в том, что деструктор C++ вызывается немедленно, а Dispose() - дальше по времени.
В большинстве случаев вам не нужно это реализовывать. GC достаточно умен, чтобы в 90% случаев выяснить, как высвободить использованные ресурсы.
Но, например: освобождение памяти, используемой потоком, не приводит к автоматическому закрытию потока, а освобождение соединения с базой данных также не закрывает его.
Реализация Dispose позволяет вам закрыть файл, когда ваш объект выпущен:
internal class Something : IDisposable {
private Stream stream;
public void SomeMethod() {
stream.Write("nskdns");
}
public void Dispose() {
if (stream != null) {
stream.Close();
}
}
Кроме того: реализация IDispose дает вам возможность использовать класс внутри оператора using:
public void Example() {
using (var x = new Something())
{
x.SomeMethod();
}
}
гарантируя, что x всегда закроет используемый поток, когда его освободит GC.
Однако я предпочитаю специальный метод Close() для класса, чтобы разрешить явное закрытие потока вместо того, чтобы полагаться на GC и вызывать Dispose()
Фактическая реализация IDisposable.Dispose вызывает реализацию базового класса Dispose(bool). Любой, кто наследует от этого класса, теперь имеет следующую задачу, если он также должен избавиться:
public override Dispose(bool disposing)
{
base.Dispose(disposing);
//my disposal code
}
Использование этого общепризнанного шаблона позволяет наследникам расширять код удаления, не нарушая удаления базового класса.
Часто, если у вас нет неуправляемых ресурсов, которыми можно распоряжаться, и вы можете позволить себе запечатать свой класс, вы можете упростить ситуацию с помощью следующего кода:
public sealed class SomeDisposable:IDisposable
{
public void Dispose()
{
//just go ahead and clean up
//because we're sealed, no-one can ever break
//this code via inheritance
}
//~SomeDisposable()
//{
// if this is being called then it will be called
// on all referenced and unrooted IDisposables too
// If everything is managed, that means we've got nothing
// left to clean up, so we can omit this Finalizer
//}
}