I'm reading "The C# Language", 4th edition, it talks about WeakReference
and Weak Event Pattern
:
CHRISTIAN NAGEL: Memory leaks often result from wrong usage of events. If client objects attach to events but do not detach from them, and the reference to the client object is no longer used, the client object still cannot be reclaimed by the garbage collector because the reference by the publisher remains. This can be avoided by (1) detaching of events when the client object is no longer used, (2) a custom implementation of the
add
andremove
accessors using theWeakReference
class holding the delegate, or (3) theWeak Event pattern
that is used by WPF with the IWeakEventListener interface.
I have doubts here: Option "(2) WeakReference
" brings NO convenience at all, comparing to "option (1) detaching of events explictly", because using WeakReference
still need explicitly calls both add
and remove
.
Otherwise, even if one of the event handler's object was assigned to null, the "orphan" object will still respond to the event - this will cause unexpected behavior.
Note: WeakReference
only helps Garbage collection in the way that event handlers' objects will not become affected by event publisher objects; WeakReference
does NOT force event handler objects get garbage collected.
Similar issue applies to Weak Event pattern, too.
Maybe this is a bit abstract, take Josh Smith's Mediator pattern (http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/) as example.
public class Mediator //...
{
public void Register(object message, Action<object> callback)
{
// notice: Mediator has no Unregister method
}
public void NotifyColleagues(object message, object parameter)
{
// ...
}
}
public class ObjectA //...
{
public string ObjectAText
{
get { return _objectAText; }
set
{
//...
_mediator.NotifyColleagues(MediatorMessages.ObjectASaidSomething, _objectAText);
}
}
}
public class ObjectB //...
{
//...
public ObjectB(Mediator mediator)
{
//...
_mediator.Register(
MediatorMessages.ObjectASaidSomething,
param =>
{
// handling event ObjectASaidSomething
});
}
}
If we have
ObjectA objectA = new ObjectA();
ObjectB objectB1st = new objectB();
objectA.ObjectAText = "John"; // objectB1st will respond to this event.
objectB1st = null; // due to delay of garbage collection, the object is actually still in memory
ObjectB objectB2nd = new objectB();
objectA.ObjectAText = "Jane"; // both objectB1st and objectB2nd will respond to this event!
Wouldn't the last line caused an unexpected behavior, due to the WeakReference
?
But if the Mediator
class provides "Unregister" method (actually I implemented one), "option (2) WeakReference
" will be no difference to "option (1) detaching of events explictly". (Mediator itself is still a useful pattern, that can penetrate hierarchy of WPF or MVVM component layers )