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

Рекомендации по обращению с IDisposable

У меня есть иерархия классов, каждый из которых может создавать объекты IDisposable.

Я добавил свойство List<IDisposable> базовому классу в этой иерархии, к которому я добавляю любые одноразовые объекты при создании. Корневой метод Dispose выполняет итерацию через этот список и вызывает Dispose для каждого элемента в своем списке и очищает список. В приложении я явно вызываю метод верхнего объекта Dispose, вызывая удаление каскада через иерархию.

Это работает, но есть ли лучший способ? Я невольно дублирую некоторые функции, уже присутствующие в рамках?

(Обратите внимание: объекты, о которых идет речь, имеют срок службы, что исключает возможность их просто вставить в блок using или утилизировать их в том же методе, в котором они созданы.)

Edit

Просто для разъяснения - я поддерживаю только те объекты, которые нужно сохранить. Некоторые из них утилизируются в том же методе, в котором они созданы, но многие из них используются таким образом, что это невозможно.

4b9b3361

Ответ 1

Пока вы правильно реализуете одноразовый шаблон (как описано здесь), этот метод в порядке.

Насколько мне известно, только теги using имеют специальную поддержку для IDisposable - в структуре не существует ничего, что реплицирует то, что вы делаете.

Ответ 2

Нет, это правильно. IDisposable предназначен для освобождения неуправляемых ресурсов и должен быть вызван как можно скорее после того, как вы закончите с экземпляром. Это распространенное заблуждение, что это не нужно, или что finailizer сделает это автоматически, когда объект будет собран мусором. Это не.

Правильный шаблон для IDisposable здесь здесь и приведен ниже для быстрой справки.

public class Resource : IDisposable 
{
    // Dispose() calls Dispose(true)
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // NOTE: Leave out the finalizer altogether if this class doesn't 
    // own unmanaged resources itself, but leave the other methods
    // exactly as they are. 
    ~Resource() 
    {
        // Finalizer calls Dispose(false)
        Dispose(false);
    }

    // The bulk of the clean-up code is implemented in Dispose(bool)
    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources here if there are any
    }
}

Ответ 3

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

Класс System.ComponentModel.Container реализует каскадный Dispose, но требует выполнения элементов IComponent. Если вы управляете своими объектами IDisposable, вы можете заставить их реализовать IComponent - для этого требуется только одно свойство Site, которое может возвращать null.

Ответ 4

Похоже на ситуацию, когда шаблон visitor может быть уместным. Хотя я никогда не понимаю утверждения о том, что он расширяет ваши классы и оставляет их неизменными, потому что я знаю только примеры, когда классы должны иметь метод AcceptVisitor или тому подобное. Кстати, это не шаблон, который мне нравится, потому что он сложный и имеет тенденцию загромождать код.

Ответ 5

Если один объект создаст много других объектов IDisposable и сохранит их право собственности на протяжении всего своего существования, шаблон, который вы описываете, может быть хорошим. Это может быть усилено тем, что ваш метод реализации класса "T RegDispos <T> (T вещь), где T: IDisposable;" который добавит одноразовое к списку и вернет его. Таким образом, можно позаботиться о создании и очистке ресурса в одном и том же выражении, заменив оператор вроде someField = someDisposType.CreateThing(); "с" someField = RegDispos (someDisposType.CreateThing());".

Если ваш класс не предоставляет публичный конструктор (требуется, чтобы посторонние использовали методы factory), и если вы используете vb.net или хотите использовать потоки-статические поля, вы можете даже комбинировать инициализацию и очистку с объявлением (например, var someField = RegDispos (someDisposType.CreateThing()); "). Чтобы это было безопасно, конструктор должен быть вызван в блок try/catch или try/finally, который может вызвать Dispose на созданных под-объектах, если сбой конструкции. Поскольку инициализаторы полей в С# не имеют доступа к параметрам конструктора (слабость языка, IMHO), единственный способ реализовать такой шаблон состоит в том, чтобы создать способ factory создать список и поместить его в поточно-статическую переменную который затем может быть прочитан статическим методом RegDispos.