Должны ли idisposable.Dispose () реализации быть идемпотентными?

Структура Microsoft.NET предоставляет интерфейс IDisposable который требует реализации метода void Dispose() . Его цель состоит в том, чтобы включить ручное или освобождение от стоимости дорогостоящих ресурсов, которое могла бы выделить реализация IDisposable . Примеры include базы данных, streamи и дескрипторы.

Мой вопрос в том, должен ли реализация метода Dispose() быть идемпотентным – если вы вызываете его более одного раза в одном экземпляре, экземпляр «удаляется» один раз и последующие вызовы не бросать исключения. В Java большинство объектов, которые имеют подобное поведение (опять-таки streamи и соединения с базой данных, которые приходят мне на ум в качестве примеров), являются идемпотентными для их операции close() , которая является аналогом метода Dispose() .

Однако мой личный опыт работы с .NET (и Windows Forms в частности) показывает, что не все реализации (которые являются частью самой платформы .NET ) являются идемпотентными, поэтому последующие вызовы для них вызывают ObjectDisposedException . Это действительно смущает меня в отношении того, как следует применять реализацию одноразового объекта. Существует ли общий ответ для сценария или зависит от конкретного контекста объекта и его использования?

если реализация метода Dispose() будет идемпотентной

Да, должно. Неизвестно, сколько раз он будет называться.

От реализации метода удаления в MSDN:

метод Dispose должен быть вызван несколько раз, не выбрасывая исключение.

Объект с хорошей реализацией IDispose будет иметь флаг логического поля, указывающий, был ли он уже удален и последующие вызовы ничего не делают (поскольку он уже был удален).

Да, также убедитесь, что другие методы classа отвечают правильно, когда они вызывается, когда объект уже удален.

 public void SomeMethod() { if(_disposed) { throw new ObjectDisposedException(); } else { // ... } } 

Из MSDN:

Разрешить метод Dispose вызываться более одного раза без исключения исключения. После первого вызова метод ничего не должен делать.

Лично – Да – я всегда делаю Dispose () идемпотент.

Во время обычного жизненного стиля объекта в данном приложении это может и не понадобиться – жизненный образ от создания к удалению может быть детерминированным и хорошо известным.

Однако одинаково, в некоторых приложениях это может быть не так ясно.

Например, в сценарии декоратора: у меня может быть одноразовый объект A, украшенный другим одноразовым объектом B. Возможно, я хочу явно распорядиться A, и все же Dispose on B также может удалить экземпляр, который он обертывает (think: streams).

Учитывая, что относительно легко сделать Dispose idempotent (т.е. если он уже настроен, ничего не делать), кажется, глупо не делать этого.