Когда разумно проверить, был ли этот объект удален и бросить ObjectDisposedException?

в классе, который реализует IDisposable, когда разумно проверить, был ли объект удален и бросить ObjectDisposedException если он есть? Во всех общедоступных методах и свойствах (кроме Dispose)? Иногда? Никогда?

5 ответов


Если объект поддерживает IsDisposed, сам этот метод никогда не должен бросать; было бы правильным для многих других методов бросать, если IsDisposed возвращает true, но исключение должно быть создано этими методами, а не IsDisposed. Можно иметь метод утилиты AssertNotDisposed, который будет бросать, если объект удален, но такое поведение ожидалось бы от метода с этим именем.

в противном случае, я бы предположил, что есть много случаев, когда это полезно имейте объект, удерживающий IDisposable объект, и иметь возможность распоряжаться внутренним объектом, сохраняя полезное состояние. Например, объект, функция которого-показать и сохранить немодальное диалоговое окно для получения информации от пользователя возможно полезно сохранить копию содержимого поля даже после того, как окно закрыто. Такой объект должен предоставлять метод "Close", который будет утилизировать внутренние одноразовые объекты, но поддерживать полезное состояние. Хотя он также может иметь метод Dispose, который будет вызывать Закройте, но также установите флаг "NoLongerValid", который вызовет свойства поля, я не думаю, что это действительно добавит какое-либо значение.

Я допускаю, что многие случаи, когда объект может содержать полезное состояние после его удаления, указывают на класс, который, возможно, следует разделить. Например, класс Font, возможно, следует разделить на одноразовый класс FontInfo (содержащий описание шрифта, но не дескриптор GDI) и IDisposable readyfont класс (наследующий FontInfo и инкапсулирование объекта шрифта GDI). Процедуры, использующие шрифт, могут проверять, является ли объект, который им был предоставлен, FontInfo или ReadyFont; в первом случае они могут создать шрифт GDI, использовать его и освободить его; в последнем случае они могут использовать объект шрифта GDI ReadyFont и освободить его. Создатель ReadyFont будет нести ответственность за обеспечение его очистки.

Как есть, я не знаю, будет ли система пытаться использовать объект GDI, связанный с свойство шрифта элемента управления при рендеринге элемента управления, но я знаю, что он не кричит, если шрифт удален (даже если он удален перед назначением его свойству шрифта!). Элементы управления, безусловно, способны создавать новые шрифты GDI при необходимости; я не знаю, всегда ли они создают новый шрифт GDI или только если старый был удален. Прежнее поведение казалось бы более эффективным, но если не закодировано тщательно, это может вызвать проблемы, если один поток попытается избавиться от Шрифт, когда другой поток использовал его.


вы должны реализовать эту проверку только в методах, которые не работают на удаленном объекте.

например:
Если ваш класс закрывает соединения с базой данных или дескрипторы файлов в Dispose, все методы, которым нужны эти подключения к базе данных или дескрипторы файлов, должны проверить, открыт ли экземпляр.


единственное, что действительно указано, это должны не что-нибудь бросить.

и любой метод, которому нужны (un)управляемые ресурсы, должен бросить.

это оставляет, на мой взгляд, только несколько спорных случаев:

  • IsOpen, IsDisposed: я бы не бросил
  • другие IsSomeStatus: это зависит.
  • Length, Count, Position : я не думаю, что замкнутый поток имеет длину, поэтому бросить

становится сложнее, когда класс объединяет (несвязанные) функции, такие как Stream и коллекция. Мы просто не должны этого делать.


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

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

в других местах это зависит от приложения, если это стоит усилий.


Как вы говорите, Я бы реализовал эту проверку во всех общедоступных методах и свойствах, кроме Dispose и IsDisposed. Это стандартный шаблон чтобы разработчик не использовал ваш тип в ошибочном представлении, что он все еще действителен.