1

I am well aware of the syntax for event subscription and unsubscription.

myEvent += myEventHandler;  // subscribe
myEvent -= myEventHandler;  // unsubscribe

I like the lambda syntax for event subscription (self contained in a block) but I cannot use this syntax if I need to unsubscribe (to avoid memory leak).

My question is therefore what kind of events stick around to require unsubscription and which ones can be ignored to be taken care of by a GC? As an example, I use the following with UWP apps, and do they need to be unsubscribed, and if so why?

  • PointerMoved event (Windows.UI.Xaml ns) for a view page (in code-behind)
  • An event from another page in the same namespace as a subscribing page. The source page with the event stays around as a menu container while subscribing pages navigate under user control.
user2921851
  • 990
  • 12
  • 26
  • 1
    I didn't mark it but this seems to be a duplicate of [this post](http://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handler-memory-leaks). A memory leak occurs when the publisher lives much longer than the subscriber, so you can "let the GC take care of unsubscribing" if your publisher is scoped such that it disappears shortly after all subscribers also fell out of scope--as Jon Skeet says in that link, "typically I find that the publisher and subscriber have roughly equal lifetimes anyway". You said, "but I cannot use this syntax if I need to unsubscribe" -- why not? – Quantic Sep 26 '16 at 18:25
  • @Quantic - answer to your last question: With the lambda syntax I am assuming that unsubscription is not possible but I could be wrong. I appreciate it if you know a syntax for unsubscribing an event with a lambda syntax. – user2921851 Sep 27 '16 at 15:17
  • Thanks @Quantic for the pointer -- yes I can see a duplicate. – user2921851 Sep 27 '16 at 15:32
  • Oh I was confusing with other syntax. There's a way if you keep a reference to the delegate around as seen [here](http://stackoverflow.com/a/1362244/5095502). – Quantic Sep 27 '16 at 15:44

1 Answers1

0

C# events are one of the least thought out features of the language. My recommendation is: never use them. If you accidentally add an event handler which has already been added, the default implementation will actually add the handler twice. This is a very hard bug to detect and troubleshoot. Also, if you accidentally remove an event handler which was never added, you get no error: it fails silently. Essentially, it is trolling you: it is telling you "yup, done!", fooling you into believing that your syllogism is correct, while in fact it is wrong. This is no way of developing software. I know many people all over the world develop software like that, and they somehow make do, all I can say is that I feel sorry for them. Don't do that to yourself.

Implement your own observer/observable pattern, asserting that nothing is added twice, and nothing is removed without first having been added. At the end of the lifetime of an observable object, assert that all observer lists are empty, meaning that all observers have bothered to unregister. Yes, garbage disposal was meant to be that magic bullet which would save us from having to worry about things like that, but well, guess what, it doesn't. Everything looks mighty fine when examining trivial examples and academic exercises on paper, but as soon as things start getting even a bit complicated, leaving things to be handled by magic just does not work anymore.

Once you have discovered that a certain observer is never unregistered from an observable object, you need to find out where the observer was allocated, and/or where it was registered. You can do that by obtaining the current stack trace and storing it within the observer, so that if the observer is later found to be alive, you can dump its stack trace. The way to obtain the stack trace is as follows: StackTrace stackTrace = new StackTrace(); Beware, this is extremely slow, (microsoft only knows why,) so use it only when it is actually needed, that is, while troubleshooting a specific class that you know has an error. Remove it as soon as the error is fixed.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • Interesting angle and thank you for taking the time. How would you implement an event subscription to, for instance, PointerMoved or similar events, then? I'm always open to a better alternative. – user2921851 Sep 27 '16 at 15:30
  • All event handlers can be represented as `Action` delegates that accept one, two, etc. parameters, let's say up to four parameters. So, all you need to do is write four different generic event managers, one for each different number of parameters. And if you are smart you can extract all of their common functionality into a common base class. Or, if you don't mind using some "magic", you can write one general purpose event manager that delivers events to any interface: http://blog.michael.gr/2011/10/intertwine-normalizing-interface.html – Mike Nakis Sep 27 '16 at 17:37