Скажите, что у Вас есть 3 класса, которые реализуют IDisposable - A, B и C. Классы A и B оба зависят от класса C.
Был бы это быть корректным, чтобы сказать, что классы A и типичная реализация B Располагают (), был бы:
public void Dispose() { if (m_C != null) m_C.Dispose(); }
Если существует экземпляр A и и экземпляр B, которые совместно используют тот же экземпляр C, как Вы преодолели бы проблему, что расположение экземпляра A повредит экземпляр B?
Последнее приложение - Если в точке 2 это - контейнер DI, который инстанцирует всех экземпляров, кто ответственен за избавление от объектов? Действительно ли это - сам контейнер? Как?
Спасибо, urig
Шаблон dispose полагается на наличие установленного "владельца", который решает, когда ресурс должен быть утилизирован.
Если A и B должны ссылаться на один и тот же экземпляр C, то только один из них должен выступать в роли "владельца".
Хотя вы можете делать то, что равносильно подсчету ссылок, я обычно нахожу, что лучше просто документировать, кто чем "владеет". Например, когда вы создаете Bitmap
с потоком, с этого момента Bitmap
владеет потоком, и вы не должны распоряжаться им самостоятельно. Это может вызвать несколько проблем, но в конечном итоге это проще, чем пытаться выкопать подсчет ссылок.
Это будет правильная реализация: однако вы можете захотеть сохранить ссылки на все объекты в зависимости от конкретного экземпляра C
в обоих A
и B
, и иметь проверку на то, что этот список пуст (за исключением текущего объекта удаления) в методе C
Dispose
.
Кто создал экземпляр? Обычно это владелец, и он должен отвечать за утилизацию экземпляра.
Скорее всего, у вас есть "внешний" класс, который создал C, а затем передал его, прямо или косвенно, в A и B. Это, вероятно, естественный кандидат, который несет ответственность за жизненный цикл C и должен распоряжаться им.
[Edit: in reply to OP's comment] Похоже, что вам стоит еще раз взглянуть на дизайн. Указывает ли это на необходимость рефактора?
У вас есть класс C, который нужно утилизировать, который используется и A, и B; должен ли у вас быть класс, который несет общую ответственность за маршалинг C через A и B, вместо того, чтобы они сами создавали C из DI-контейнера? Или же C действительно больше похож на синглтон. Нужно ли его вообще утилизировать?
Я думаю, все, что я хочу сказать, это то, что это может указывать на дизайн, который нуждается в небольшом изменении; посмотрите еще раз критическим взглядом.
Два метода, о которых я мог бы подумать:
Только один экземпляр должен быть владельцем, и он отвечает за утилизацию. Экземпляр, не являющийся владельцем, должен получить ссылку на C с помощью такой функции, как Attach, и не должен ее удалять.
Обычно я делаю это таким образом, обычно меня принимают, и это определенно работает. Однако, если его удалил другой объект, проверка на null не остановит повторный вызов dispose, потому что он не будет нулевым. Однако утилизация C должна защищать от множественных вызовов.
Очень хороший вопрос. Сразу же приходит в голову, что нужна логика, чтобы знать, сколько счетчиков в данный момент находится на этом объекте, чтобы его собственные процедуры удаления могли защитить себя. Семафоры делают это, но они тяжелые.
Я также хотел бы спросить, где это можно увидеть в реальном примере, может быть несоответствие дизайна. Обновление: , как уже упоминали другие, все сводится к проблеме дизайна - вы получаете аналогичный эффект при использовании CCW, кто-то другой освобождает базовый COM-объект, где другие пользователи все еще могут его использовать.
Проверка на нуль не поможет, так как если B избавится от C, это не обновит ссылку A.
Вы должны убедиться, что только один из классов имеет право собственности на C. Этот класс-владелец затем отвечает за его удаление.
Как правило, класс, создающий C, должен быть и классом, который его утилизирует.
Дополнение в последнюю минуту - Если в пункте 2 это контейнер DI, который создает все инстанции, кто несет ответственность за утилизация предметов? Это сам контейнер? Как?
Да, контейнер владеет любыми IDisposable
объектами, которые он создает. Контейнер удаляет эти объекты, когда он сам удаляется. Все контейнеры DI уже должны делать это по умолчанию.
Иногда структура DI дает вам возможность взять на себя ответственность. Например, в Autofac вы можете запросить инъекцию Owned
, а затем вы можете спокойно вызвать Owned
, когда закончите с объектом. Это особенно полезно, если вы динамически создаете экземпляры с помощью внедренной фабрики Func
. Обратите внимание, что такие «собственные экземпляры» не предназначены для совместного использования.
В дополнение к тому, что сказал Джон, создатель является владельцем и должен распорядиться Одноразовым.
В данном случае это контейнер, и контейнер отвечает за утилизацию компонентов. Не каждый компонент поддерживает это (или, по крайней мере, не каждый полностью). Замок Виндзор . Также Autofac поддерживает это.