Могу ли я сделать так, чтобы время жизни объекта C # зависело от другого объекта?

У меня есть объект (Delegate), который должен оставаться в живых (не собирать мусор), пока жив другой объект (TargetObject). Я хочу, чтобы Delegate собирал мусор, когда TargetObject собирается (или, по крайней мере, доступен для сбора).

Сложность в том, что мне не нужно ссылаться на Delegate из TargetObject, поскольку я хочу, чтобы он работал для существующих объектов, не знающих о Delegate, и я не хочу влиять на время жизни TargetObject. Это вообще возможно?

Спасибо.

Изменить: спасибо за ответы. Попробую уточнить, что я задумал.

Я пытаюсь реализовать слабые события, но я не поклонник WeakEventManager (особенно IWeakEventListener). Я хочу иметь слабую ссылку на обработчик событий делегата (Delegate), который указывает на метод в объекте TargetObject. Должна быть сильная ссылка на Delegate, пока TargetObject жив, чтобы поддерживать Delegate в живых, но если что-то с более длительным временем жизни ссылается на Delegate, он поддерживает TargetObject в живых (устраняя цель слабого события).

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

Изменить Изменить: изменено 'A' на 'Делегат' и 'B' на 'TargetObject'


person AndrewS    schedule 17.09.2009    source источник
comment
Что это означает: я хочу, чтобы это работало для существующих объектов, не знающих B?   -  person Stefan Steinegger    schedule 17.09.2009
comment
Когда B ссылается на A, а A - это существующий объект, A не нужно знать B, не так ли?   -  person Stefan Steinegger    schedule 17.09.2009
comment
Я немного не понимаю, что такое A, а что B. Не могли бы вы отредактировать, чтобы называть их издателем и подписчиком, чтобы было очевидно, что есть что? Или добавьте небольшой пример кода :)   -  person Jon Skeet    schedule 17.09.2009
comment
Виноват. Теперь A - «Delegate», а B - «TargetObject», где Delegate указывает на метод TargetObject. Надеюсь, это немного лучше :)   -  person AndrewS    schedule 17.09.2009


Ответы (5)


Святой некро, но ConditionalWeakTable делает именно то, что вам нужно. Он позволяет связывать значения с произвольными ключами, с парами "ключ-значение" как эфемероны (именно то, что вы были искали, 2 года назад ... к сожалению, .NET 4 тогда не был доступен).

Даже без ConditionalWeakTable решением могло бы быть Dictionary<WeakReference, Delegate> с периодической очисткой для удаления старых мертвых значений (т.е. всякий раз, когда Словарь увеличивается в размере вдвое, удаляйте все мертвые пары). С этим решением, если делегат ссылается на TargetObject, это предотвратит сбор пары - проблема ConditionalWeakTable была разработана для решения.

Просто разместите это на случай, если кто-то сочтет это полезным.

person Mania    schedule 13.12.2011

Для меня это звучит как проблема дизайна. Если B не нужно знать об экземпляре A, почему вас волнует, жив A или нет?

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

Если вы можете объяснить, почему вы считаете, что вам это нужно, мы можем предложить лучший подход.

person Jon Skeet    schedule 17.09.2009
comment
Я определенно избегаю подхода с использованием таймера :) Сейчас я думаю, что мне придется сделать ссылку B на A, но было бы неплохо другое (более чистое) решение. - person AndrewS; 17.09.2009

Почему бы вам просто не сослаться на A из B?
Это сохранит жизнь A и не требует, чтобы A знал о B ...

person Niklas    schedule 17.09.2009
comment
Извините, мой вопрос должен был быть прочитан Я хочу, чтобы он работал для существующих объектов, не знающих о A. A может ссылаться на B, но не наоборот. - person AndrewS; 17.09.2009

Я не думаю, что хороший дизайн - иметь «живой» объект, на который нет никаких ссылок.

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

Я не вижу для этого чистого решения, но, возможно, некоторые из супер-существ в StackOverflow найдут решение.

person Philippe Leybaert    schedule 17.09.2009

Бросьте событие в метод деструктора (финализации) B и напишите обработчик для этого события, которое убивает A.

person Console    schedule 17.09.2009
comment
Для этого потребуется ссылка с B на A и конкретная реализация, которой я пытаюсь избежать. - person AndrewS; 17.09.2009
comment
Вам не понадобится ссылка, вам просто понадобится что-то в вашем приложении, которое может отреагировать на событие от B и сказать A, чтобы он умер. Прочитав ваши обновления, я полагаю, что ваше дело сложнее, чего я не совсем понял. :) - person Console; 17.09.2009