Использование одноразового шаблона для очистки классов-членов IDispose

Часть одноразового шаблона включает следующий способ.

protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.
        disposed = true;
    }
}

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

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


person Jonathan Wood    schedule 10.08.2015    source источник
comment
Вы можете взглянуть на Fody.Janitor. Он автоматически реализует это для вас.   -  person Aron    schedule 10.08.2015


Ответы (2)


Вы должны вызывать Dispose в управляемом разделе (т. е. только когда disposing истинно).

Часть руководства в Шаблон удаления в Руководстве по разработке платформы:

Логический параметр disposing указывает, был ли метод вызван из реализации IDisposable.Dispose или из финализатора. Реализация Dispose(bool) должна проверять параметр перед доступом к другим ссылочным объектам [...]. Доступ к таким объектам должен осуществляться только при вызове метода из реализации IDisposable.Dispose (когда параметр удаления равен true). Если метод вызывается из финализатора (удаление равно false), доступ к другим объектам невозможен. Причина в том, что объекты финализируются в непредсказуемом порядке, поэтому они или любые их зависимости уже могли быть финализированы.

Другой полезный ресурс: Реализация метода Dispose.

person Frank Boyne    schedule 10.08.2015

Стандартный способ удаления членов класса, реализующий IDisposable, выглядит следующим образом:

public class Foo : IDisposable
{
    // MemoryStream implements IDisposable
    private readonly Stream _stream = new MemoryStream();

    private bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            _stream.Dispose();
        }

        _disposed = true;
    }
}

Чтобы уточнить, очистка управляемых ресурсов означает, что сам ресурс реализует IDisposable (как это делает MemoryStream выше). MemoryStream/Stream содержит базовый неуправляемый ресурс, и логика его очистки уже реализована за вас. Нет необходимости очищать неуправляемые ресурсы в Foo.

person rexcfnghk    schedule 10.08.2015
comment
зачем вам логическое удаление, если оно всегда верно? - person IronHide; 13.01.2020
comment
Потому что для незапечатанного класса вы можете передать false в Dispose(bool), когда производный класс имеет финализатор. Реализация метода Dispose - person rexcfnghk; 14.01.2020