Unsubscribing from events - unsubscription or null? - c#

Is this approach correct? I want only one subscription to this events. When I try using unsubscription -=, for some reason events are actually adding and every time it's more.PresentationViewModel is not disposed when closing associated window so I can't rely on IDisposable this time yet it is implemented and events are disposed there also - maybe an overkill.
I want to know if assigning null is going to bring any side effect I might not want.
Thank you.
public PresentationViewModel ViewModel
{
get
{
if (_viewModel != null) return _viewModel;
_viewModel = (PresentationViewModel) DataContext;
_viewModel.OnNavigatedToHandler = null; // <-------------------
_viewModel.OnNavigatedToHandler += OnNavigatedToHandler;
_viewModel.OnNavigatedFromHandler = null; // <-------------------
_viewModel.OnNavigatedFromHandler += OnNavigatedFromHandler;
return _viewModel;
}
}
And previously I added unsubscription this way which resulted in many calls of this methods:
_viewModel.OnNavigatedToHandler -= OnNavigatedToHandler;
_viewModel.OnNavigatedToHandler += OnNavigatedToHandler;
_viewModel.OnNavigatedFromHandler -= OnNavigatedFromHandler;
_viewModel.OnNavigatedFromHandler += OnNavigatedFromHandler;

Is this approach correct ... for some reason events are actually adding...
To prevent your event handler from being invoked when the event is raised, you need to
unsubscribe from the event. In order to help prevent any resource leaks, you should unsubscribe from events, read more here about this.
As for your comment about, for some reason events are actually adding, the reason for this is you are not unsubscribing and therefore the object is kept alive by this reference. In return, doing this without unsubscribing would create a memory leak.
As already mention in the comments, do not assign null to the event as, "it will unsubscribe ALL handlers, even ones that your code didn't subscribe." as Matthew Watson has pointed out. Jon Skeet notes, it'll effectively clear the list of subscribers, which means no handlers whatsoever are called at this point, Matthew Watson also mentions this in his comments.
With all this in mind, -= is the proper way of unsubscribing an event and should be used.
References:
How to subscribe to and unsubscribe from events c#
Should I unsubscribe from events

Related

Event handler is removed by GC when subscribed to external event

For work, I have to subscribe to an external event and handle it when it comes by. I have no problem doing all that but I noticed that after the first GC pass, the event handler I added seemingly gets removed. I won't be able to receive the next event after the collection.
If I manually trigger the GC then remove and add the handler, I will properly receive the next event.
I tried using KeepAlive and SuppressFinalize from the GC to no avail. I also tried to add the handler as a lambda, but it still gets removed after the first garbage collection.
example code (pseudo, for reference only)
private externalLibrary.Server server = new Server();
private externalLibrary.DataHandler handler; //delegate is assigned in constructor
public bool Subscribe(){
//...
server.Data.Received += handler;
}
With this setup, I receive events until the first GC.
My ugly workaround looks like this:
ResetHandler(){
server.Data.Received -= handler;//It seems to already be removed by GC but better be safe than sorry
server.Data.Received += handler;
}
And in the code when I finished my processing of the event, I do:
GC.Collect;
ResetHandler();
This allows me to circumvent the problem. I would like to find a better solution or know what I am doing wrong.
Please note that this is my very first question here.
Thank you for your input.

Do I need to unsubscribe events in my Form?

I'm trying to understand how a Control events are unsubscribed. Suppose I have a textbox and I have subscribed the TextChanged event using the WinForms designer.
Is the TextChanged event automatically unsubscribed in the Textbox destructor, or must I explicitly unsunscribe to avoid memory leaks?
public void InitializeComponents()
{
...
this.emailTextBox.TextChanged += emailTextBox_TextChanged;
...
}
public override void Dispose()
{
if( disposing )
{
// DO I REALLY NEED THIS LINE?
this.emailTextBox.TextChanged -= emailTextBox_TextChanged;
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
Any object which subscribes to events from a longer-lived object should implement IDisposable and should unsubscribe those events when it is Disposed. Conceptually, there's no reason why objects shouldn't unsubscribe from all events when they are disposed, since doing so would avoid problems if an object whose events one subscribed turned out to live longer than expected. Unfortunately, the event architecture in .NET provides no mechanism for conveniently ensuring that events get cleaned up when objects are disposed, and having code unsubscribe a bunch of events when an object is disposed may make it harder to make sure that the few events which really need to be cleaned up are among the ones that are.
In this situation I beleive it is OK not to unsubscribe because the TextBox to which you're subscribing is wholly contained within the parent control (or that's what I'm assuming.)
Therefore when no further references to the parent control exist, there won't be any external references to the TextBox and so both objects will become eligible for GC.
There are situations when you should unsubscribe from events to prevent memory leaks because the reference held by the event (in it's list of subscribers) is just the same as any other reference and would prevent the subscriber from being GC'd.
Such situations can occur when an object subscribes to an event on an external object (i.e. not owned by this object.) In this situation the subscriber would only become eligible for GC after the subscribed-to object was eligible for GC.
The events are actually a list of event handlers (function delegates). So when you write this:
this.emailTextBox.TextChanged += emailTextBox_TextChanged;
You actually add your delegate emailTextBox_TextChanged to the list of existing delegates associated to the TextChanged event.
What this means is that when the textbox is disposed, this list will be disposed too, so you don't need to unsubscribe events in that case, and you won't have memory leaks.
So to answer your question, the event isn't really unsubscribed in the textbox destructor, but you don't need to do it explicitly.
The only case in which it will be useful to unsubscribe is when you don't want your function to handle the event anymore during execution, but I think I've never actually needed to do that.
Yes, you better unsubscribe. As official docs say (here)
In order to prevent resource leaks, you should unsubscribe from events before you dispose of a subscriber object. Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds that reference, garbage collection will not delete your subscriber object.

Anonymous event handlers and disposing

I have a rather short question about anonymous event handlers:
This is the code that I have:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += (o, e) => { RemoveTestControl(ctrl); };
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.SomeEvent -= _Control_SomeEvent;
}
Is this code above fine, or should the code be rewritten in order to remove the Disposed Event Handler?
Something like this:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += _Control_Disposed;
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.Disposed -= _Control_Disposed;
ctrl.SomeEvent -= _Control_SomeEvent;
}
Generally, the only situation where you need to remove the event handlers from an object in order for it to be eligible for garbage collection is when the publisher object (the one defining the event) lives longer than the subscriber object (the one containing the event handlers). In such a situation the GC won't be able to release the subscriber when it goes out of scope since it's still being referenced by the publisher.
In this case, assuming this is WebForms or WinForms, the publisher (that is the Control object), is most likely a child object of the subscriber (probably a Page or a Form), which will be the first to go out of scope taking all its associated objects with it. Hence there's no need to remove the event handlers.
It always feels cleaner to me to unsubscribe from events, even in situations where I know the subscribers always outlive the publisher (the object raising the event): the event will never be raised again, the publisher is no longer reachable and can be collected.
Then again, how many people go to the trouble of unsubscribing every event handler in e.g. a WinForms application? The object references point from the publisher to the subscribers, not the other way around, so the publisher can be collected while the subscribers live on. It doesn't present the same danger as the opposite situation, where a long-lived publisher (e.g. a static event) can wastefully keep potentially large subscribers alive long after they could have been collected.
If you want/need to unsubscribe, then the requirement to unsubscribe the same delegate makes anonymous event handlers a bit of a pain. The Reactive Extensions solve this problem in a neat way: rather than having to remember the delegate you subscribed, subscribing returns an IDisposable which unsubscribes when disposed. Chucking all your subscriptions into a CompositeDisposable lets you unsubscribe everything with just one Dispose call.
Both codez are fine, but I like second as a matter of personal preference. It reads clearer than the first.
On top of it with the first code, there's anonymous lambda delegate and it gets a current reference to ctrl. That code may behave unexpectedly depending on situation and compile optimisation settings: whether or not the call is inlined or not.
Not to mention that there's architectural problem with the code: you have ControlOwner and a bunch of Child Controls. I take it you're adding child controls to ControlOwner at runtime, and then trying to react to their behavivour by subscribing ControlOwner to the childControl events. This is fine for events like _ButtonClicked etc. But not good for Dispose. Let the child control handle it's disposing on itself, the OwnerControl doesn't need to know about it. Not to mention that it may not exist at a time ChildControl[n].Dispose is called.
In short:
* it is better to leave dispose event on ChildControl alone and do all clean up in ChildControl.Dispose
* it is not necessary to unsubscribe from events. Event dispatcher will check if subscriber is alive.

Should I unsubscribe from events? [duplicate]

This question already has answers here:
Is it bad to not unregister event handlers?
(2 answers)
Closed 9 years ago.
I have 3 questions concerning events:
Should I always unsubscribe events that were subscribed?
What happens if I do NOT?
In the below examples, how would you unsubscribe from the subscribed events?
I have for example this code:
Ctor: Purpose: For database property updates
this.PropertyChanged += (o, e) =>
{
switch (e.PropertyName)
{
case "FirstName": break;
case "LastName": break;
}
};
and this: Purpose: For GUI-binding wrap the model into viewmodels
ObservableCollection<Period> periods = _lpRepo.GetDailyLessonPlanner(data.DailyDate);
PeriodListViewModel = new ObservableCollection<PeriodViewModel>();
foreach (Period period in periods)
{
PeriodViewModel periodViewModel = new PeriodViewModel(period,_lpRepo);
foreach (DocumentListViewModel documentListViewModel in periodViewModel.DocumentViewModelList)
{
documentListViewModel.DeleteDocumentDelegate += new Action<List<Document>>(OnDeleteDocument);
documentListViewModel.AddDocumentDelegate += new Action(OnAddDocument);
documentListViewModel.OpenDocumentDelegate += new Action<int, string>(OnOpenDocument);
}
PeriodListViewModel.Add(periodViewModel);
}
Well, let's take the last question first. You can't reliably unsubscribe from an event that you've subscribed to directly with a lambda expression. You either need to keep a variable around with the delegate in (so you can still use a lambda expression) or you need to use a method group conversion instead.
Now as for whether you actually need to unsubscribe, it depends on the relationship between the event producer and the event consumer. If the event producer should live for longer than the event consumer, you should unsubscribe - because otherwise the producer will have a reference to the consumer, keeping it alive for longer than it should be. The event handler will also keep getting called for as long as the producer produces it.
Now in many cases that's not a problem - for example, in a form the button that raises the Click event is likely to live for about as long as the form on which it's created, where the handler is typically subscribed... so there's no need to unsubscribe. This is very typical for a GUI.
Likewise if you create a WebClient solely for the purpose of a single asynchronous request, subscribe to the relevant event and start the asynchronous request, then the WebClient itself will be eligible for garbage collection when the request has finished (assuming you don't keep a reference elsewhere).
Basically, you should always consider the relationship between the producer and the consumer. If the producer is going to live longer than you want the consumer to, or it's going to continue raising the event after you're no longer interested in it, then you should unsubscribe.
1) It depends. Usually it's a good idea, but there are typical cases where you don't need to. Basically, if you are sure that the subscribing object is going to outlive the event source, you ought to unsubscribe, otherwise this would create an unnecessary reference.
If however your object is subscribing to its own events, like in the following:
<Window Loaded="self_Loaded" ...>...</Window>
--then you don't have to.
2) Subscribing to an event makes additional reference to the subscribing object. So if you don't unsubscribe, your object might be kept alive by this reference, making effectively a memory leak. By unsubscribing you are removing that reference. Note that in the case of self-subscription the problem doesn't arise.
3) You can do like that:
this.PropertyChanged += PropertyChangedHandler;
...
this.PropertyChanged -= PropertyChangedHandler;
where
void PropertyChangedHandler(object o, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "FirstName": break;
case "LastName": break;
}
}
You don't have to desubscribe from an event when the instance that is subscribing has the same scope as the instance that is being subscribed to.
Lets say you are a form and you are subscribing to a control, these two together form a group. However, if you have a central class that manages forms and you have subscribed to the Closed event of that form, these do not form a group together and you must desubscribe once the form is closed.
Subscribing to an event makes the subscribed instance create a reference to the instance being subscribed to. This prevents garbage collection. So, when you have a central class that manages form instances, this will keep all forms in memory.
WPF is an exception because it has a weak event model where events are subscribed to using weak references and it will not hold the form in memory. However, it is still best practice to desubscribe when you are not part of the form.
You may take a look at this article on MSDN. Quote:
To prevent your event handler from
being invoked when the event is
raised, simply unsubscribe from the
event. In order to prevent resource
leaks, it is important to unsubscribe
from events before you dispose of a
subscriber object. Until you
unsubscribe from an event, the
multicast delegate that underlies the
event in the publishing object has a
reference to the delegate that
encapsulates the subscriber's event
handler. As long as the publishing
object holds that reference, your
subscriber object will not be garbage
collected.
1.) Should I always desubscribe events that were subscribed?
Usually yes. The only exception is when the object on which you subscribed isn't referenced anymore and will be garbage collected soon.
2.) What happens if I do NOT?
The object on which you subscribed will hold a reference to the delegate, which in turn holds a reference to its this pointer, and thus you'll get a memory leak.
Or if the handler was a lamda it will hold onto whatever local variables it bound, which thus won't be collected either.

Event subscription to a static instance. How to ensure GC

I'm fixing a User control component using the .NET 1.1 framework.
There are many instances of this user control referencing a singleton wrapping a COM resource.
They subscribe to events from this resource.
I suspect that the reason why we are having a degrading performance is because the singleton is maintaining a reference to the user control classes even after their respective windows are gone. Thus preventing GC.
They unsubscribe the event in their finalize method.
Hence I suspect a chicken and egg problem. The finalize wont execute because they are being referenced through their event subscription in the longer lived Singleton, preventing GC.
Where in a User Control should I perform the event unsubscribe to make it eligible for GC?
I do not own the application hosting the user control.
You should unsubscribe when the control is disposed, really. If you can't easily modify the Dispose method yourself, you could add an event handler to the Disposed event:
ComSingleton.Foo += FooHandler;
this.Disposed += delegate { ComSingleton.Foo -= FooHandler; };
If you want to subscribe to events using anonymous methods or lambda expressions, you'll need to use a separate local variable so that you can refer to it again:
EventHandler tmp = delegate { Console.WriteLine("Something happened"); };
ComSingleton.Foo += tmp;
this.Disposed += delegate { ComSingleton.Foo -= tmp; };
An alternative is to use "weak event handlers" - there are many articles about this on the web; here's one which goes into a fair amount of detail.

Categories