I have been wondering whether it would be worth implementing weak events (where they are appropriate) using something like the following (rough proof of concept code):
class Foo {
private WeakEvent<EventArgs> _explodedEvent = new WeakEvent<EventArgs>();
public event WeakEvent<EventArgs>.EventHandler Exploded {
add { _explodedEvent += value; }
remove { _explodedEvent -= value; }
}
private void OnExploded() {
_explodedEvent.Invoke(this, EventArgs.Empty);
}
public void Explode() {
OnExploded();
}
}
Allowing other classes to subscribe and unsubscribe from events with the more conventional C# syntax whilst under the hood actually being implemented with weak references:
static void Main(string[] args) {
var foo = new Foo();
foo.Exploded += (sender, e) => Console.WriteLine("Exploded!");
foo.Explode();
foo.Explode();
foo.Explode();
Console.ReadKey();
}
Where the WeakEvent<TEventArgs>
helper class is defined as follows:
public class WeakEvent<TEventArgs> where TEventArgs : EventArgs {
public delegate void EventHandler(object sender, TEventArgs e);
private List<WeakReference> _handlers = new List<WeakReference>();
public void Invoke(object sender, TEventArgs e) {
foreach (var handler in _handlers)
((EventHandler)handler.Target).Invoke(sender, e);
}
public static WeakEvent<TEventArgs> operator + (WeakEvent<TEventArgs> e, EventHandler handler) {
e._handlers.Add(new WeakReference(handler));
return e;
}
public static WeakEvent<TEventArgs> operator - (WeakEvent<TEventArgs> e, EventHandler handler) {
e._handlers.RemoveAll(x => (EventHandler)x.Target == handler);
return e;
}
}
Is this a good approach? are there any undesirable side effects to this approach?
That's a bad idea because:
See the linked answer. It's a 95% duplicate but not quite enough to close the question I think. I'll quote the most relevant parts:
There also is a semantic difference and non-determinism that would be caused by weak references. If you hook up () => LaunchMissiles()
to some event you might find the missiles to be launched just sometimes. Other times the GC has already taken away the handler. This could be solved with dependent handles which introduce yet another level of complexity.
I personally find it rare that the strong referencing nature of events is a problem. Often, events are hooked up between objects that have the same or very similar lifetime. For example you can hook up events all you want in the context of an HTTP request in ASP.NET because everything will be eligible for collection when the request has ended. Any leaks are bounded in size and short lived.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With