avrà un evento con abbonati che impedirà a un oggetto di essere sottoposto a GC?

2

Ho un oggetto, che ha un evento che a sua volta ha abbonati. So che gli oggetti sottoscriventi non riceveranno GC poiché il delegato che hanno memorizzato per l'evento è connesso a loro, quindi li mantiene connessi al grafico dell'oggetto, fino a quando non li si annulla esplicitamente. Questo è logico, poiché altrimenti non accadrà nulla di buono quando scatta l'evento.

Questo vale anche per il proprietario dell'evento?
Vorrei pensare che non lo facesse, dal momento che gli oggetti sottoscrittivi non hanno una connessione ad esso, per quanto ne so. E ancora usando il buon senso (che so non correlare necessariamente alla realtà IT): Nulla di male può accadere se il proprietario dell'evento è GC, solo l'evento non sparerà mai più.

Questa supposizione è corretta?

    
posta Mark 28.07.2014 - 12:45
fonte

1 risposta

3

Sì, credo che la tua ipotesi sia corretta. Ho anche provato a scrivere un codice (brutto) per testare questa ipotesi:

class MyClassWithEvent
{
  public event Action Fired;

  void OnFired()
  {
    var d = Fired;
    if (d != null)
      d();
  }
}
class MyClassSubscribing
{
  void M()
  {
  }

  public void DoSubscribe(MyClassWithEvent mcwe)
  {
    mcwe.Fired += M;
  }
}

static class Test
{
  static void Main()
  {
    WeakReference<MyClassWithEvent> wrMcwe;
    WeakReference<MyClassSubscribing> wrMcs;
    GetWeakRefs(out wrMcwe, out wrMcs);

    // no garbage collect should occur just now, for we are not allocating new objects

    // keep one of the objects alive; also try keeping the other one alive instead
    MyClassSubscribing keepAlive;
    wrMcs.TryGetTarget(out keepAlive);
    //MyClassWithEvent keepAlive;
    //wrMcwe.TryGetTarget(out keepAlive);

    // loop not really needed
    while (DateTime.Today.Year < 3000)
    {
      GC.Collect();
      MyClassWithEvent x;
      MyClassSubscribing y;
      Console.WriteLine("Is 'class with event' alive: {0}; is 'class subscribing' alive: {1}", wrMcwe.TryGetTarget(out x), wrMcs.TryGetTarget(out y));
    }
    Console.WriteLine(keepAlive); // or just: GC.KeepAlive(keepAlive);
  }

  static void GetWeakRefs(out WeakReference<MyClassWithEvent> wrMcwe, out WeakReference<MyClassSubscribing> wrMcs)
  {
    var mcwe = new MyClassWithEvent();
    wrMcwe = new WeakReference<MyClassWithEvent>(mcwe);
    var mcs = new MyClassSubscribing();
    wrMcs = new WeakReference<MyClassSubscribing>(mcs);
    // link the two objects
    mcs.DoSubscribe(mcwe);
    // objects mcs and mcwe could be collected after this method exits
  }
}

Output: Mantiene la scrittura:

Is 'class with event' alive: False; is 'class subscribing' alive: True

Se si mantiene vivo l'altro oggetto, non viene raccolto alcun oggetto, come sapevamo.

Entrambi gli oggetti vengono raccolti se escludiamo del tutto le righe keepAlive .

    
risposta data 28.07.2014 - 14:32
fonte

Leggi altre domande sui tag