How to deinitialize a FrameworkElement? - c#

We have a class which derives from FrameworkElement and which is not under our control.
This class registers eventhandlers in the OnInitialize method.
What is the pattern to properly clean this class up, since FrameworkElement does not provide a counterpart to OnInitialize?
It remains rooted since no part of it removes the EventHandler causing a leak.

There's no such thing as "deinitializing". Initialization methods are used when it isn't possible to fully initialize an object in its constructor, because it depends on data that isn't available during construction. In these cases construction is broken in two phases: the first step is executed in a parameterless constructor, the second in an initialization method, like OnInitialize, after the external data becomes available
What you describe is object disposal, which is performed by calling an object's Dispose method. A well-written class should clean up its data, release any external resources and release any event handlers.
Visual elements typically have another step in their lifecycle, handled by the OnLoad/OnUnload methods. The Load step occurs when an element is actually placed in XAML view and connected to the other UI elements. Event handlers should be registered in the OnLoad method and removed in the OnUnload method.
If the element has no Dispose method , you may be able to raise the Unload event to force the cleanup, although this is a bit of a hack:
control.RaiseEvent(new RoutedEventArgs(FrameworkElement.UloadedEvent))

Use weak event pattern. In particular, subscribe to events using WeakEventManager implementations (or, better, its generic version WeakEventManager<TEventSource, TEventArgs>, if .NET 4.5 is an option).

Use Dispatcher.ShutdownStarted event.
Add this to the constructor:
Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
And add your cleanup code to this method:
private void Dispatcher_ShutdownStarted(object sender, EventArgs e)
{
Stop();
}

Related

How to prevent an event handler being called before a constructor's finished?

If I hook an event in a constructor, is there any possibility that the handler might be invoked by another thread before it's finished with the constructor?
e.g.:
private List<string> changes;
public MyClass(INotifyPropertyChanged observable) {
observable.PropertyChanged += this.Handler;
// Another thread changes a property at this point
this.changes = new List<string>();
}
private void Handler(object sender, PropertyChangedEventArgs e) {
this.changes.Add(e.PropertyName); // Breaks, because the list's not there yet
}
(Yes, I know it's trivial to avoid a problem in this example, I've got some more complex cases than this I'd like to make fully thread-safe)
I could probably just put a lock(obj) round both the event handler and the body of the constructor, but that feels clumsy and I suspect it's probably prone to deadlock somehow.
Is there a clean & reliable way of doing this?
ECMA-335 doesn't obligate a CLI to provide guarantee that the initialization changes which are made in a constructor should be visible before the constructor completion:
It is explicitly not a requirement that a conforming implementation of the CLI guarantee that all state updates performed within a constructor be uniformly visible before the constructor completes (see there, section I.12.6.8).
So the brief answer: avoid a subscription of an instance event handlers inside a constructor because it implies an exposure of the instance to external consumers with no guarantee that the instance is ready for consumption.
In details: typically semantic of a constructor implies only state initialization that is getting internal data of an instance into consistent state (when all its invariants are true and it's ready for consumption by other objects). The mechanism of events in C# in essence is adaptation of observer pattern which implies number of interactions between its participants and making of subscription is one of those interactions and as any other interaction with other object it should be avoided in a constructor when the instance isn't guaranteed to be initialized. You correctly noticed the possible scenario when it can become a problem but even with applying of protection mechanisms like reordering or synchronization, it cannot be guaranteed 100% safe, because it may not be provided by a CLI implementation or even if provided there is still possibility of scenarios when a constructor fails to complete for a reason not dependent on code inside the constructor, for example because of ThreadAbortException.
Of course there can be some relaxed requirements to design dictated by some well-known constraints (for example you can be 100% sure that your event publisher is implemented in the way which excludes critical scenarios) but in general case I'd suggest to make separation of construction and subscription scenarios when there is separate method, which is part of public contract and which is purposed only for making subscriptions.
How about using a thread-safe collection (like ConcurrentQueue) combined with the null conditional operator?
Thread-safe delegate invocation
Use the ?. operator to check if a delegate is non-null and invoke it in a thread-safe way (for example, when you raise an event).
class MyClass
{
private ConcurrentQueue<string> changes;
public MyClass(INotifyPropertyChanged observable)
{
observable.PropertyChanged += this.Handler;
// Another thread changes a property at this point
this.changes = new ConcurrentQueue<string>();
}
private void Handler(object sender, PropertyChangedEventArgs e)
{
this.changes?.Enqueue(e.PropertyName);
// Nothing breaks, changes during construction are simply not recorded
}
}

Anonymous method for event handler not a leak?

Whenever you add a delegate to an event handler, you should remove it later, right? So if you attach an anonymous method to an event, does this create an event handler leak since you can't later remove it? This code sample from http://msdn.microsoft.com/en-us/library/0yw3tz5k%28VS.80%29.aspx seems to imply that this an okay practice though.
// Create a handler for a click event
button1.Click += delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };
Is this really an okay practice?
Whenever you add a delegate to an event handler, you should remove it later, right?
Not necessarily, no. Often you want the event handler to stay valid for as long as the event itself can be raised - that's certainly very common with UIs.
Is this really an okay practice?
Absolutely, so long as you don't need to unhook the handler. Think about the point at which you'd unhook the event handler. If it's "when the form (or button, or whatever) is elegible for garbage collection" then what benefit is there in removing the handler? Just let it be garbage collected with the form...
Whenever you add a delegate to an event handler, you should remove it later, right?
Well, not always. There are two reasons why you'd want to remove an event handler that you're adding:
You're constantly adding handlers to the same instance that are short lived. If you didn't remove them then there would be more and more handlers added, when most of them aren't needed.
Your handler internally holds onto a reference to an object who's lifetime is much shorter than the lifetime of whatever object the event belongs to, and the event handler won't be (or can't be) called once that other object goes out of scope. Leaving the event handler attached will either force it to stay in memory longer than desired, or possibly result in using an object that's "stale" and shouldn't be used anymore. (For example, if the resource has already been disposed you don't want that event to fire anymore.)
The reason #2 is an issue is because of how Garbage Collection works in C#. It marks all objects that it can be 100% sure are in scope as "alive", and then follows everything that any of those "alive" objects reference as also being "alive" until it's followed every reference in every live object. Anything that was never marked as "alive" is then deemded "dead" and eligible for garbage collection.
When you have an event handler attached to an event that delegate contains two things, an instance of an object and a method to run on that object. That referenced object won't be able to be garbage collected until either:
The object with the event is no longer "alive".
You remove the event handler (i.e. the reference to) your delegate, allowing your object to be freed earlier.
That said, a significant percentage of cases don't apply to either of those, so there's no need to bother removing the event handlers.
As an example, I often see people removing event handlers just before the event object goes out of scope. That's pointless. If the object is out of scope there's no problem with it holding onto references to...whatever.
Now, if you are in one of those few situations in which you do need to unsubscribe the event handler, and you're using an anonymous method you need to...not. Just create a class that can make it a named method and use that.
Subscibing to event with anonymous method (or lambda expression) potentially can lead to memory leaks, but not in this case.
In this case compiler will generate an anonymous method inside current class and you don't have any memory related issues as long as your button will not live much longer than your object.
The use of inline anonymous delegates as event handlers does prevent those handlers being removed, as you stated. This can indeed cause problems, especially if the delegate comes from a different object. If you had a class A with a public event E, and E was subscribed to by a class B (that has no containing/contains relationship to A) attaching an anonymous handler H, H is technically a member of B, and so as long as it's referred to (by being attached to A's event), B won't be GCed. B's lifetime becomes tied to A's, and if you didn't want or expect that you now have a memory leak.
Now, that's not always a problem. If B contains A, or the other way around, then A and B's lifetimes are already tied together anyway; in your case, the button itself will very probably be disposed of before its containing control that attached the handler. Similarly, A and B could be long-lived objects (say, the program's main form and a data repository) and won't be GCed until the program terminates anyway. As long as you never have to care about a difference in lifetime between A and B, and you never need to detach H from E to stop exhibiting whatever behavior H has, then you can attach all the anonymous handlers you like.

Remove event listener from local variable

Do I have to worry about removing event listeners assigned to local variables?
Consider the following sample:
var zipUtil = new ZipUtil();
zipUtil.ProgressChanged += ZipUtil_ProgressChanged;
I'm creating an instance of the ZipUtil class which is stored as a local variable within a method. Do I have to remove the listener (zipUtil.ProgressChanged -= ZipUtil_ProgressChanged;) before the method terminates or is it okay to skip the step?
No, you don't have to remove that event handling method.
When adding an event handler to an event, a reference from the (object containing the) event to the event handler is created, not the other way round. Once zipUtil goes out of scope, the event handler will not make any difference pertaining to references to zipUtil.
Two lines of code are never enough to make the call accurately. But it is very unlikely you'll need to unsubscribe explicitly. There are two possible problem scenarios:
the class may fire its event at an inopportune time, after your object is disposed for example. That's fairly unlikely in this scenario, surely the ZipUtil class stops raising ProgressChanged events when you stop calling its methods. Not completely out of the question, it could do work on a background thread for example. Not visible from your snippet.
you can have a garbage collection problem due to events. The event delegate keeps an implicit reference to your class object, necessary so it can call ZipUtil_ProgressChanged() method. If it is an instance method, not clear from your snippet. That reference will keep your outer class alive. But not the other way around. Given that the lifetime of the ZipUtil object is restricted to the method and you surely want your outer class to survive at least to the end of the method, this should never be a problem.
High odds that ZipUtil implements IDisposable btw. Do make sure you use the using statement if it does.

Assumptions on event raising

Imagine the following class:
class A
{
public event EventHandler AnyEvent;
}
You create an instance of class A, and attach some event handlers. Now if AnyEvent gets raised, I would not assume, that the event handlers are performed on another thread, than the thread I created the object. This would be of prime importance, if you created the object on a GUI thread, and the event handler performs operations on GUI elements. This would force me to use appropriate invocation patterns.
It really becomes evil, if you use interfaces defining events:
interface B
{
event EventHandler SomeEvent;
}
Now one implementation could raise the event from the original thread, the next from a second thread. This can cause your application to successfully work with the one, and fail with the other implementation.
I think coding should always be transparent - this is not! And if I don't create another thread, I do not assume, that my methods are performed from any other than my home thread.
Are there any aspects I did not consider? Any that would invalidate my assumption?
There is no magic with events. Events are handled on the thread that raises them. It has nothing to do with the thread that creates the object.
Threading is the responsibility the consumer of the class, not the writer of the class, so your assumption is incorrect.
One should assume a class is not thread-safe unless it is documented to be thread-safe. Even most built-in .NET classes are not thread safe unless they say they are.
It is up to the consumer of the class to be aware of threading.
Calling events is just calling some method (or collection of methods) using a mechanism such as function pointers.
Events are completely oblivious to the thread that attached them, and don't have any other information that could lead to properly Invoking the methods on the right thread.
Maybe you are drawing your assumptions from COM days?
Handler callbacks for events are on the same thread that raised the event.

Eventhandlers and application lifetime objects in c# - should I unhook?

Say I've got an object that exists for the duration of an application. Let's call it GlobalWorker. GlobalWorker has events e.g. UserLoggedIn to which other objects can subscribe. Now imagine I've got a Silverlight page or an asp.net page or something, that subscribes to the UserLoggedIn event when it is constructed.
public SomePage()
{
GlobalWorker.Instance.UserLoggedIn += new EventHandler(OnUserLoggedIn);
}
private void OnLoggedIn(object sender, EventArgs e)
{
}
Does the existence of this event prevent the page from being garbage collected? If so, what's the best pattern to use in this instance: weak event-handlers, move the subscription to the Load event and unsubscribe in the UnLoad event?
Use Weak Events.
This is a common problem in WPF and it is good you have thought about it.
Yes the behavior prevents the page from being GC.
The reason being is that UserLoggedIn will hold a reference to SomePage indefinitely. There is no explicit removal of the handler and since weak events are not being used it will not implicitly get removed either.
You can use weak events as another poster stated, you can also re-think your design to some degree and see if you can functionalize or encapsulate the eventing behavior. Perhaps the data is all that needs to be global in this instance (user credentials), where as the event can be kept isolated.
You could also de-register in the handler itself if this was a one-off event you cared about. It really boils down to your specific need and instance, weak event pattern is the pattern to deal with this application wide but does not mean you have to use that pattern in each and every instance this problem surfaces.

Categories