В любой данный момент каждый экземпляр каждого типа, который реализует IDisposable, должен иметь по крайней мере одну (и обычно ровно одну) сущность, которая может вызвать вызов Dispose через некоторое время после того, как он больше не нужен, и до того, как он станет полностью и в конечном итоге заброшен. Если в вашем типе есть поле типа IDisposable, но можно ожидать, что что-то еще может избавиться от любого экземпляра IDisposable, на который он может ссылаться, то вам не следует вызывать Dispose для этого поля самостоятельно. Если у вашего типа есть поле IDisposable, никто не будет использовать этот объект, как только вы покончили с ним, и никто не должен его утилизировать, тогда вы должны вызывать Dispose для объекта, когда он вам больше не нужен. Во многих случаях ваш объект будет нуждаться в другом объекте до тех пор, пока ваш объект не понадобится ни одному другому объекту, и способ, которым ваш объект обнаружит это, - это когда кто-то еще вызывает Dispose для него (после чего он будет вызывать Dispose для других объектов).
Один шаблон, который иногда может быть полезен, состоит в том, чтобы класс выставлял событие Disposed, которое возникает при каждом вызове Dispose. Это может быть полезно, если, например, другой объект дает вашему объекту ссылку на IDisposable, которая ему потребуется некоторое время, а затем объект, предоставивший вам IDisposable, завершает работу с ним. Он не может утилизировать объект, пока ваш объект все еще нуждается в нем, и ваш объект не собирается его утилизировать (поскольку ваш объект не будет знать, сделано ли с ним объект, предоставивший IDisposable). Если класс, предоставивший вашему классу IDisposable, перехватывает обработчик Disposed вашего объекта, то обработчик событий может затем заметить, что вашему объекту больше не нужен IDisposable, и либо немедленно его удалить (если ваш объект был последним, который нуждался в нем), либо установите флаг так, чтобы, когда другой пользователь закончил работу с объектом, он был удален).
Еще один шаблон, который может быть полезен, если у вашего объекта будет определенный набор одноразовых объектов, которые он будет хранить в течение всей своей жизни, - это хранить список объектов IDisposable, а затем метод Dispose итерировать по списку и размещать в нем объекты. Каждый элемент в списке должен быть расположен в своем собственном блоке Try / Catch; если возникает исключение, выдается исключение CleanupFailureException (пользовательский тип), которое имеет первое или последнее такое исключение, как его InnerException, а также содержит список всех исключений, которые возникли как пользовательское свойство.