Для чего именно нужен 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 
    //}
}

Используется с using блок компилятором C#.

Другие вопросы по тегам