Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Правильная реализация Dispose

#c_sharp #net


Доброго времени суток! У меня есть такой вопрос. Допустим, у меня есть класс, реализующий
интерфейс IDisposable. У этого класса есть какой-то управляемый ресурс, который тоже
реализует этот интерфейс. Вот минимальный код моего класса.

class MyClass : IDisposable
{
    private SomeContext _context = new SomeContext();

    public void Dispose() 
    {
        if(_context != null)    
            _context.Dispose();
    }
}


И тут у меня возник вопрос. Насколько правильна эта реализация? Точнее насколько
она неправильна и чем это грозит? (везде где смотрел я видел более сложную реализацию
Dispose паттерна). Вроде бы имеется всего одно IDisposable поле (предполагается что
оно корректно реализует этот паттерн в своих внутренностях), и чтобы освободить ресурс
корректно, достаточно просто в нужное время вызвать метод Dispose для поля _context.
В чем я не прав? Применима ли такая простая реализация на практикке и чем она вообще
плоха? 
    


Ответы

Ответ 1



Да, в этой схеме всё верно. Неуправляемых ресурсов нет, финализатор не нужен. Dispose вызов прокидывает дальше, т. е. своё дело делает. А вообще, рекомендую почитать: http://sergeyteplyakov.blogspot.ru/2011/09/dispose-pattern.html, особенно раздел Упрощенная версия Dispose паттерна, который очень похож на этот вопрос.

Ответ 2



Всё правильно, но можно убрать проверку на null. Если класс сконструировался, то _context не равно null, т. к. new не может вернуть null. Итого: class MyClass : IDisposable { SomeContext _context = new SomeContext(); public void Dispose() => _context.Dispose(); } Обратите внимание, иногда уместно использовать такую конструкцию: class MyClass : IDisposable { bool isDisposed = false; void EnsureSelfAlive() { if (isDisposed) throw new ObjectDisposedException(); } SomeContext _context = new SomeContext(); public void Dispose() { isDisposed = true; _context.Dispose(); } } и в каждом публичном методе в начале вызывать EnsureSelfAlive(). Позволяет отлавливать какое-то количество ошибок. Проверять isDisposed в Dispose не нужно, т. к. _context должен уметь «пережить» множественные вызовы _context.Dispose().

Комментариев нет:

Отправить комментарий