2009-07-17 2 views
8

В C# /. NET есть ли способ получить уведомление до того, как объект, на который указывает слабая ссылка, разрушен? В принципе, я хочу, чтобы объект был собран, но делайте что-то прямо перед тем, как объект будет уничтожен, без изменения кода для добавления деструкторов (поскольку я не буду точно знать, какие типы объектов будут предъявлены к моему коду). неC#: Уведомление перед WeakReference собрано?

Спасибо, Роберт

ответ

5

Вы не можете этого сделать. Однако, что вы можете сделать, это наблюдать, когда приближается GC (в CLR v3.5Sp1 есть новые GC API, что позволяет вам это делать, GCNotifications)

+0

Я предполагаю, что это так же естественно, как любое, чтобы обновить сериализованные данные. Спасибо за информацию! –

6

Нет нет никакого способа достижения этой функциональности.

После нескольких спекуляций я не верю, что возможно реализовать функцию в том виде, как вы описываете.

Учтите, что в точке, в которой объект, хранящийся с помощью WeakReference, собран, больше нет ссылок (следовательно, оно доступно для коллекционирования). Для того, чтобы какое-либо событие вам пригодилось, он должен был предоставить объект как часть события. Это означает, что ссылка перешла от коллекционной к не коллекционируемой. Нет ничего, что останавливало бы обработку кода от повторной ссылки на этот объект. Следовательно, объект больше не может считаться собираемым. CLR необходимо будет сделать второй проход на объекте, чтобы обеспечить его сбор.

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

Было бы неправильным использование наименования, чтобы заявить, что это событие было поднято непосредственно перед тем, как был собран объект. Просто потому, что любой обработчик может помешать этому собирать, установив новую ссылку на объект. Вместо этого это должно быть «ObjectMaybeAboutToBeCollected». Это, вероятно, не даст вам поведения, которое вы ищете.

+0

Прохладный, спасибо ... можете ли вы придумать какие-либо способы получить аналогичную функциональность, отличную от WeakReferences? –

+0

@Robert, кроме формы деструкторов/распоряжаться, я ничего не могу придумать с головы – JaredPar

+0

Я абсолютно согласен, во всяком случае, слабые события могут сделать трюк! Один крошечный улов, они не существуют на C#, поэтому вы должны его реализовать (это немного сложно, но в принципе возможно). –

0

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

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

+0

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

+2

Это все еще кажется немного напуганным. Если вы периодически отправляете сериализованные данные на сервер, почему бы просто не связать объект, который отвечает за сериализацию, поддерживать (неслабкую) ссылку на зарегистрированные объекты и выпускать их после их загрузки? Учитывая непредсказуемость времени уничтожения, вы все равно не захотите зависеть от него для целостности данных. –

+0

Им нужно постоянно сериализоваться так часто, пока они живы/меняются. Это предпочтения пользовательского интерфейса Silverlight (т. Е. Ширина столбцов и т. Д.), Поэтому, пока элементы пользовательского интерфейса все еще существуют, их состояние необходимо сохранить на сервере. –

0

Для того, что вы описываете, финализаторы будут лучше подход.

0

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

Поскольку это невозможно, наилучшим возможным подходом может быть, что все ссылки «Я заинтересован в этом объекте» указывает на легкий объект-оболочку, который, в свою очередь, указывает на реальный объект и имеет «Слабые» ссылки указывают на другую оболочку, которая также указывает на реальный объект. Первая обертка должна содержать ссылку на вторую, но не наоборот. Первая оболочка должна иметь финализатор, который запускает соответствующий код, когда он выходит за рамки.

К сожалению, я не видел никаких реализаций такой стратегии. Есть несколько важных моментов для рассмотрения. Среди них: (1) финализаторы никогда не должны ждать на замках и не делать ничего, что могло бы вызвать исключение; (2) код, который обращается к другим объектам, которые могли выйти из сферы действия, должен быть подготовлен для возможности того, что они, возможно, уже были доработаны, находятся в процессе окончательной доработки, ждут завершения или остаются живые ссылки в другом месте; (3), если финализатор хранит привязанные ссылки к завершаемому объекту, который был найден подходящим для сбора мусора, такой объект может быть завершен, даже если существует ссылка на живую.

6

.Net 4.0 имеет решение, которое вам необходимо: ConditionalWeakTable. Вот короткая программа, которая демонстрирует эту идею. (обсуждено here)

using System; 
using System.Runtime.CompilerServices; 

namespace GCCollectNotification 
{ 
    class ObjectToWatch { } 

    class Notifier 
    { 
     public object ObjectToWatch { get; set; } 
     ~Notifier() { Console.WriteLine("object is collected"); } 
    } 

    class Program 
    { 
     private ConditionalWeakTable<object, Notifier> map 
      = new ConditionalWeakTable<object, Notifier>(); 

     public void Test() 
     { 
      var obj = new ObjectToWatch(); 
      var notifier = map.GetOrCreateValue(obj); 
      notifier.ObjectToWatch = obj; 
     } 

     static void Main(string[] args) 
     { 
      new Program().Test(); 

      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 

      // "object is collected" should have been printed by now 

      Console.WriteLine("end of program"); 
     } 
    } 
}