C# – Will Event Subscribers Prevent Object from Being Garbage Collected?

ceventgarbage-collectionnet

I have an object, which has an event which in turn has subscribers.
I know that the subscribing objects won't get GC'ed since the delegate they stored for the event is connected to them, thus keeping them connected with the object graph, until one explicitly unsubscribes them. This is only logical since otherwise nothing good will happen when the event is fired.

Does this apply to the Event-owner as well?
I would think it does not, since the subscribing objects do not have a connection to it, to my knowledge.
And again using common sense (which I know does not neccessarily relate to IT-reality):
Nothing bad can happen if the event-owner is GC'ed, only the event will never fire (again).

Is this assumption correct?

Best Answer

Yes, I believe your assumption is correct. I also tried to write some (ugly) code to test this hypothesis:

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: Keeps writing:

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

If you keep the other object alive, neither object is collected, as we knew.

Both objects are collected if we leave out the keepAlive lines entirely.

Related Topic