1

Say I have a class defined as:

class MyWrapper<T> where T : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChange(String propname)
  {
    handlePropertyChanged(this, new PropertyChangedEventArgs(propname));
  }

  private void handlePropertyChanged(object sender, PropertyChangedEventArgs e)
  {
      var handler = PropertyChanged;
      if (handler != null)
      {
          handler(sender, e);
      }
  }

  private T _backing;
  public MyWrapper(T backing)
  {
    _backing=backing;
    _backing.PropertyChanged+=handlePropertyChanged;
  }

  ...Reasons for wrapping the class...
}

This class sets a delegate on the PropertyChanged event on the backing object. From my understanding this delegate has a pointer to the instance of MyWrapper. Does this mean that instances of MyWrapper will have a lifetime no shorter than the baking object?

If so, is there a way around this?

Taemyr
  • 3,407
  • 16
  • 26

2 Answers2

2

If you really want to keep a reference without preventing GC, have a look at weak references. Those allow you to keep a reference to an object as long as it exists (you always need to explicitly check if the object still exists and extract the "real", strong reference).

In the case of delegates, WeakEvent is appropriate.

However, I'd suggest another approach as well. If the event handler really doesn't do anything (as in your sample code), you can skip it entirely, and declare PropertyChanged like so:

public event PropertyChanged
{
    add { _backing.PropertyChanged += value; }
    remove { _backing.PropertyChanged -= value; }
}

Alternatively, if the handler is important (e.g. it translates inputs etc.), you could consider using an explicit dispose pattern that will unregister any event handlers:

public void Dispose() { _backing.PropertyChanged -= handlePropertyChanged; }

When you're done using the wrapper object, just call Dispose (or, if there's a fixed scope, use using). This is simplified - a proper dispose pattern is a bit more complicated, but isn't really necessary if you're not dealing with unmanaged resources.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • It's the MyWrapper object that I want should be collected. Other than the delegate I see no reference to that. – Taemyr May 27 '16 at 08:34
  • @Luuan You might want to update the answer - WeakEvent and/or dispose pattern might be the correct answer. The code above does something; it ties the parts of the program that makes changes on backing object(and have no knowledge of the wrapping object) together with the object that access through the wrapper(and don't have any knowledge of the actual wrapped object). – Taemyr May 27 '16 at 08:51
  • WeakEvent's definititly seems the way to go. Especially since the Manager for PropertyChanged comes ready made. – Taemyr May 27 '16 at 08:57
  • @Taemyr Updated :) – Luaan May 27 '16 at 10:07
  • I was not aware that you could have custom add/remove on events. That's neat. – Taemyr May 27 '16 at 10:17
  • @Taemyr Yeah, that's what I meant when I said "pass the delegate through". Since `event`s are just methods (the add and remove methods, respectively), they can even be a part of an interface, which you can also exploit to help with your abstractions. – Luaan May 27 '16 at 10:30
1

Yes, a reference held by another property to the event handle would prevent the MyWrapper class instance from being garbage collected. Only when all references to the handler are released (e.g. when these instances are also eligible for GC) can the MyWrapper instance be freed from memory.

This question is similar to one posted before: Do event handlers stop garbage collection from occuring?

Edit: To answer your comment about the delegate, you assign handlePropertyChanged as a delegate to backing, which creates an external reference to MyWrapper. Therefore, MyWrapper will not be GC'ed until that reference is removed.

There a few ways to manage this:

  1. Use a weak reference: https://msdn.microsoft.com/en-us/library/system.weakreference(v=vs.110).aspx
  2. Remove the reference to the delegate/event as soon as it is no longer needed.
Community
  • 1
  • 1
Wicher Visser
  • 1,513
  • 12
  • 21
  • I think you misunderstand my question. I am asking if the delegate that I have set on the baking field will prevent the MyWrapper object from being freed. I don't quite care that objects with references to the event handle of the MyWrapper instance prevents the wrapper from being freed. – Taemyr May 27 '16 at 08:38