I was wondering if setting an object to null will clean up any eventhandlers that are attached to the objects events...
e.g.
Button button = new Button();
button.Click += new EventHandler(Button_Click);
button = null;
button = new Button();
button.Click += new EventHandler(Button_Click);
button = null;
etc...
Will this cause a memory leak?
If there are no other references to button anywhere, then there is no need to remove the event handler here to avoid a memory leak. Event handlers are one-way references, so removing them is only needed when the object with events is long-lived, and you want to avoid the handlers (i.e. objects with handler methods) from living longer than they should. In your example, this isn't the case.
Summary: You need to explicitly unsubscribe when the event source/publisher is long-lived and the subscribers are not. If the event source out-lives the subscribers, all registered subscribers are kept "alive" by the event source (not collected by the GC) unless they unsubscribe (and remove the reference to themselves from the event publisher's notification list)
Also this is a duplicate of
Is it necessary to explicitly remove event handlers in C# and has a good title n answer. So voting to close.
See the discussion here under "The final question: do we have to remove event handlers?"
Conclusion: you should remove
delegates from events when they reach
outside the class itself; i.e. when
you subscribe to external events, you
should end your subscription when you
are done. Failing to do so will keep
your object alive longer than
necessary.
Related
I am using windows forms.
My C# application contains 100 user controls. I show/hide one of those 100 user controls at a time when I need to and hide the rest.
Each one of those user controls has 30 buttons and I subscribe to button event as following in the constructor:
public UserControl1()
{
InitializeComponent();
button1.Click += new EventHandler(MyButtonClick);
button2.Click += new EventHandler(MyButtonClick);
.
.
button30.Click += new EventHandler(MyButtonClick);
}
void MyButtonClick(object sender, EventArgs e)
{
// do something
}
So when I run the Application all the 100 User controls subscribe to the 30 buttons event and some of the user controls subscribe to the event but they are never used during the use of the application.
I read something about unsubscribing events here and Here but some answers say you should unsubscribe because it cause memory leak and some say you don't have to, therefore the answer is still not clear.
My question is do I have to unsubscribe from button events after using it for example: when I show/hide a user control. If yes, how can I subscribe from button event when a user control is shown and unsubscribe when it is not shown.
Why unsubscribe?
It comes down to the lifespan of the subscriber (UserControl) compared to the subscribe (Button). The subscribe hold a reference to the subscriber. So if the subscribe have longer lifespan then the subscriber it will memory leak the subscriber.
So in your case you should ask if the Buttons will persist longer then the UserControl. If the Buttons have shorter on equal lifespan then no need to unsubscribe. Otherwise you will memory leak the UserControl.
In your case I guess that you don't need to unsubscribe.
If I got your question right - each control subscribing only on IT'S OWN children (30 buttons). The case when forgetting to unsubscribe is bad idea is when publisher (button) will live longer than subscriber (user control). Why? Because publisher will store link to subscriber and will prevent that subscriber to be disposed by Garbage Collector. In your case button will never live longer than it's parent - user control, so you don't need to unsubscribe.
In your case there is no reason to worry. The two examples that you linked to have a different 'kind' of event, like this: if object A changes, then method X should be called, so X can act on or process the change in object A.
For example A = inventory of a product; if the count of A goes to zero then it can no longer can be sold, or new items must be ordered, etc.
When responding to changed data, then the need to call X could cease to exist at some point in time, and then it may be beneficial to unregister the event, especially if there is no other way to break or disable the link.
However in a User Interface scenario such as yours, the need to call X usually stays present. If needed it can be controlled in another way, e.g. by disabling the button or by hiding it. There is really nothing expensive about having a link between a button and a method. The only reason to break the link would be 'I no longer want X to be called EVER if the button is clicked'.
You do not normally have to unsubscribe from events. That said, there are exceptional cases, when this is required.
This typically look like this: you have a long-lived object, that creates short-lived objects and attaches their methods to handle its (or some other long-lived object's) events. Alternatively, you create an object and attach its method to an event of different object with longer lifespan.
Now, when those short-lived objects go out of scope, they will still be attached to the event, so Garbage Collector will not reclaim them as long as the long-lived object (to whose event they are subscribed) is in scope. This is because it keeps their references to the objects that are supposed to handle its events.
In your case (and most other typical ones), the handlers are members of the class that owns the child control, so there is no risk of artificially prolonging any object's live. You do not need to explicitly unsubscribe here.
You don't really have to unsubscribe, but you should. The way to unsubscribe would be:
//adding
EventHandler myHandler = new EventHandler(MyButtonClick);
button1.Click += myHandler;
//removing
button1.Click -= myHandler;
I want to conditionally unhook an event handler. Is this the right way to do it:
tb.TextChanged -= textBoxIntName_TextChanged;
?
This seems to be sensible, as hooking it up required:
tb.TextChanged += textBoxIntName_TextChanged;
...but it also seems that what corresponds to the "Delphi way" makes as much or more sense (but alas, it does not compile):
tb.TextChanged = nil;
You cannot assign events - only attach (+=) and remove (-=) operations are available for clients.
Read more about events here.
Also C# specification says:
Since += and -= are the only operations that are permitted on an event
outside the type that declares the event, external code can add and
remove handlers for an event, but cannot in any other way obtain or
modify the underlying list of event handlers.
I have the following line of code in a usercontrol:
Application.Current.RootVisual.MouseLeftButtonDown += RootClicked;
When it's defined the parent usercontrol is no longer collected by the GC or destroyed, the RootClicked event keeps firing even after it should no longer be active.
if I add:
Application.Current.RootVisual.MouseLeftButtonDown -= RootClicked;
The issue is no longer present.
Any ideas why this is? Is there a function I should explicitly remove the event?
This is a normal behaviour and a common source of memory leaks in .NET.
When you attach an instance method of object A to an event of object B, you are adding in the list of event receivers the instance of A, so the garbage collector cannot free up the object A until you remove the handler or you release every reference to both object A and B.
This is an expected and normal behaviour.
There are two common ways to solve the problem:
1) You unsubscribe object A from the event when you don't need the object A anymore.
2) You use weak events, like WPF does.
Weak events are usually implemented with the class WeakReference, you can find more informations on the web.
What happens:
Application.Current.RootVisual.MouseLeftButtonDown event keeps reference to the control in its invocation list so the control is not eligible for collection (since it is referenced by the delegate).
Solution:
Subscribe to Unloaded event after you subscribe to the MouseLeftButtonDown event and unsubscribe form the MouseLeftButtonDown event in the Unloaded event handler:
...
Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
this.Unloaded += Control_Unloaded;
...
void Control_Unloaded(object sender, RoutedEventArgs e)
{
Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;
}
OR more concise:
Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
this.Unloaded += (s, e) => Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;
This is a known behavior, but most developers are not aware of it. You should look into the Weak Event Pattern for information on how to get around this limitation in a more graceful (if more coding-intensive) fashion than having to manually remove event handlers.
Often in code I see a line of code, I have an idea it do something about event but not clearly know what it does.
Is it possible that I can attach form A's load event in Form B with this, or what is its benefit?
this.CGForm .Load +=new EventHandler(CGForm_Load);
Yes, it clearly has to do with events.
.Load in this case the the Form.Load event. The += operator adds one event handler to the event. An event can have many event handlers at the same time. Event handlers are just regular method that can be anywhere in your code base. When the event fires all subscribed methods will be called, one after the other.
I see no particular good reason to have FormA listen to the Load event of FormB, but other events might be more interesting, like the Form.Closed event. This is a way to have FormA react to changes in FormB.
Edit
Note that this causes FormA to hold a reference to FormB and FormB won't be garbage collected until FormA releases the reference to FormB (with
this.CGForm .Load -=new EventHandler(CGForm_Load);, note the -=) this is a common cause for memory leaks in .NET.
Subscribing to events from other forms is a "code smell" that can be a potential structure problem with your code. In some cases it is required, but if you have it all over the place your code will be hard to understand and maintain.
What this line means is that you subscribe the method CGForm_Load() to the this.CGForm.Load event. The method CGForm_Load() is the event handler or the callback.
After you run this line, every time the event is raised (in this case - every time the form is loaded), CGForm_Load() will be called automatically.
In order to unsubscribe a callback, use -= like this:
this.CGForm.Load -= new EventHandler(CGForm_Load)
Once an event callback is unsubscribed, the next time the event is raised (if the form is loaded again) the callback will no longer be called.
I find the following metaphor helpful: An event is like a power outlet, and callbacks are like power plugs. Subscribing is like connecting the plug to the outlet, and unsubscribing is like pulling it out. While there is a connection, all invocations of the event trigger the callback.
It simply adds the GCForm_Load method to the Load event on the CGForm. Under the hood when the CGForm is loaded code like the following will execute. Whenever this happens all event subscribers (in this case the method being subscribed here as CGForm_Load) will be invoked.
<pseudocode>
class CGForm
{
public EventHandler<FormLoadedEventArgs> Load;
private void SomeMethodThatLoadsTheForm()
{
LoadForm();
var loadHandlers = Load;
if (loadHandlers != null)
{
loadHandlers(new FormLoadedEventArgs(...));
}
}
}
</pseudocode>
this.CGForm .Load +=new EventHandler(CGForm_Load); subscribes the event handler delegate CGForm_Load to the Load event of the CGForm object.
Documentation about subscribing to events can be found at http://msdn.microsoft.com/en-us/library/ms366768(v=vs.80).aspx .
And index of information about how events work in .NET can be found at http://msdn.microsoft.com/en-US/library/awbftdfh(v=VS.80).aspx
i am using textchanged event and i disable it where i don't need as following
object.Event -= new System.EventHandler(myHandler);
//my code which doesn't need event handler
object.Event += new System.EventHandler(myHandler);
i used many times like this. but i needed sometimes 2 disable code like this:
object.Event -= new System.EventHandler(myHandler);
object.Event -= new System.EventHandler(myHandler);
of course i finished it with 2 enable code
object.Event += new System.EventHandler(myHandler);
object.Event += new System.EventHandler(myHandler);
i don't know yet why i needed 2 times remove event handler but it worked great.
but in 1 case i got problem.
it doesn't work with 2 or more disable code.
my question is, how can i watch this eventhandler if it needs just one -= code or more?
or how can i manage it?
i always worked like this, to make sure that i always leave event handler as first time
object.Event -= new System.EventHandler(myHandler);
//my code which doesn't need event handler
object.Event += new System.EventHandler(myHandler);
My advice would be to stop removing and re-adding the event handler, and instead add a flag to your event handler itself which inhibits whatever activities you need to inhibit during these sections of code.
You can either have a single boolean flag, or use some kind of reference count, depending on how you need to cope with nesting.
If there's some reason why you can't change the existing event handler, what about creating a new event hander which you attach to Event, and call the old one from that?
You need to remove an event handler as many times as you've added it - and you won't be able to tell when that is, as the subscriptions are effectively hidden from you.
Ideally, just make sure you only subscribe as many times as you need to, and it should be obvious how many times you need to unsubscribe too. Usually this will be once. It's somewhat odd that you ended up with two subscriptions to start with... I suspect that may indicate a bug somewhere in your code.
Note that unsubscribing using an event handler which isn't already subscribed is a no-op.
(Will's idea of the event handler itself knowing whether or not it's really "active" is a good one too, btw.)