Unsubscribe to lambda event [duplicate] - c#

I have the following code to let the GUI respond to a change in the collection.
myObservableCollection.CollectionChanged += ((sender, e) => UpdateMyUI());
First of all is this a good way to do this?
Second: what's the code to unsubscribe from this event? Is it the same but with -= (and then the complete anonymous method again)?

First of all... yes its a good way of doing it, it's clean, small form and easy to read & understand... the caveat of course is "Unless you later want to unsubscribe".
I believe Jon Skeet pointed out before that
"the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods."
So if you need to unsubscribe from the event at a later time, you'd be best to actually create a delegate instance so you can hang onto the reference for later.
var myDelegate = delegate(sender, e){UpdateMyUI()};
myObservableCollection.CollectionChanged += myDelegate;
myObservableCollection.CollectionChanged -= myDelegate;

If you need to unsubscribe from an event, you need an instanced reference. Unfortunately, that means you can't use that particular syntax.

It's an ok way to go, unless myObservableCollection is going to live longer than 'this', in which case you could end up with a memory leak, as the delegate which is created behind the scenes will conserve a reference to your 'this', which will keep it alive. If you are repeatedly creating and 'destroying' whatever is listening to the event, you will find that they aren't being collected by the garbage collector.
If this is a problem, you can go the route suggested in the answers, conserving a reference to the handler, which you must create first.
Another solution is to use weak references to create an event handler which will allow the subscriber to be collected if there are not other references. I've explored this solution in this question and answer.

Related

How to keep event subscriptions from blocking garbage collection

I have a class (Model) an object of which serves as a blueprint for (short-lived) objects of another class (ModeledRelation). Model defines an event ModeledRelation always subscribes to in order to be notified when Model changes, so ModeledRelation objects can reflect these changes 1:1.
Now ModeledRelation objects are used somewhere else for some time and then finally go out of scope. But because the event still holds a reference to them they prevent garbage collection.
Of course I formally want the objects to be GC'ed already if the event is the only reference left. I know I can unsubscribe from the event in ModeledRelation.Dispose but that would require explicitely calling Dispose and this feels a little too crafty for a purely managed class. I also want to be safe in the case that the ModeledRelation object silently slips out of scope and not have a memory leak then.
Maybe I am thinking in a totally wrong direction and this has to be done differently.
You should look at the Weak Event Patterns :
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/weak-event-patterns
Upon meditating about the problem throughout the day I have recognized what is the core issue about my approach: subscribing to the event during construction of ModeledRelation. This leads to the natural conclusion that unsubscription has to be done during object destruction... which never happens because event still points to the object and GC is blocked.
Instead the right solution to the problem is to subscribe to the event when the ModeledRelation is actually used (in my case added to another object's collection). Because then the natural moment to unsubscribe is when it ceases to be used (if it is removed from the collection of the other object). If it is reused afterwards it will resubscribe, whereas if it slips out of scope it will just be GC'ed because no events point to it anymore!

Adding and Removing Event Handler in .net

i recently created a sample application, wherein i implemented the events and delegates, when the Properties value is changed this event will raise, i have a question regarding events
Does event objects are created in memory? or they are just static object which gets removed once the event is fired?
Is it necessary to remove the handler once the event is executed, to free-up resources. does removing handler once done, boost's up the application performance, i am talking about the application which are using lots of events
Events do take memory and are not garbage collected until after you unsubscribe from them. They are a common cause of memory leaks.
Events can be both static and instance bound. Subscribers to the event are never removed while the event broadcaster is alive, unless implicitly done so, usually with the -= operator.
Yes, yes and yes. If you don't clean-up your subscribers you have a memory-leak waiting to happen.
If all this is a concern to you perhaps you could look into the WeakEvent pattern.
events are like delegates ( with another layer of protection) .
when you register to an event - you are actually making a reference to another object.
this object can't go through GC because you made a reference to it !
it isnt "un-referenced".
but your object CAN go through GC. ( if un-referenced).
so you end up with memory leak.
you should manually remove the reference .

Can I make a C# object's lifetime depend on another object?

I have an object (Delegate) which needs to stay alive (not garbage collected) while another object (TargetObject) is alive. I want Delegate to be garbage collected when TargetObject is collected (or at least available for collection).
The difficulty is that I don't want to need to reference Delegate from TargetObject since I want it to work for existing objects unaware of Delegate, and I don't want to affect the lifetime of TargetObject. Is this at all possible?
Thanks.
Edit: Thanks for the responses so far. I'll try to clarify what I'm up to.
I'm trying to implement weak events but I'm not a fan of the WeakEventManager (particularly IWeakEventListener). I want to hold a weak reference to a delegate event handler (Delegate) which points to a method in object TargetObject. There needs to be a strong reference to Delegate while TargetObject is alive to keep Delegate alive, but if something with a longer lifetime references Delegate, it keeps TargetObject alive (defeating the purpose of the weak event).
It would be nice if objects subscribing to weak events didn't have to have any special implementation details such as having to hold on to a collection of delegates.
Edit Edit: Changed 'A' to 'Delegate' and 'B' to 'TargetObject'
Holy necro, but ConditionalWeakTable does just what you needed. It allows associating values with arbitrary keys, with the key value pairs as ephemerons (exactly what you were looking for, 2 years ago now.. unfortunately .NET 4 wasn't available then).
Even without ConditionalWeakTable a solution could have been a Dictionary<WeakReference, Delegate>, with periodic sweeping to remove old dead values (ie whenever the Dictionary doubles in size, remove all dead pairs). With this solution if a Delegate refers to TargetObject it'd prevent collection of the pair though - a problem ConditionalWeakTable was designed to resolve.
Just posting this in case anyone might find it useful.
This sounds like a design issue to me. If B doesn't need to know about the instance of A, why do you care about whether A is alive or not?
You can possibly do this using a container object with a weak reference to B and a strong reference to A, and a timer periodically checking whether the weak reference is still alive... but it would be a pretty grotty hack.
If you can explain why you think you need this, we may be able to suggest a better approach.
Why don't you just reference A from B?
That will keep A alive and does not require A to be aware of B...
I don't think it's good design to have an "alive" object that doesn't have any references to it.
You could always create a static List with references to objects that should stay alive, but of course you'd have to manage that yourself.
I don't see a clean solution for that, but maybe some of the super-beings on StackOverflow will come up with a solution.
Throw an event in the destructor (finalize) method of B, and write a handler for that event that kills A.

How to unsubscribe from an event which uses a lambda expression?

I have the following code to let the GUI respond to a change in the collection.
myObservableCollection.CollectionChanged += ((sender, e) => UpdateMyUI());
First of all is this a good way to do this?
Second: what's the code to unsubscribe from this event? Is it the same but with -= (and then the complete anonymous method again)?
First of all... yes its a good way of doing it, it's clean, small form and easy to read & understand... the caveat of course is "Unless you later want to unsubscribe".
I believe Jon Skeet pointed out before that
"the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods."
So if you need to unsubscribe from the event at a later time, you'd be best to actually create a delegate instance so you can hang onto the reference for later.
var myDelegate = delegate(sender, e){UpdateMyUI()};
myObservableCollection.CollectionChanged += myDelegate;
myObservableCollection.CollectionChanged -= myDelegate;
If you need to unsubscribe from an event, you need an instanced reference. Unfortunately, that means you can't use that particular syntax.
It's an ok way to go, unless myObservableCollection is going to live longer than 'this', in which case you could end up with a memory leak, as the delegate which is created behind the scenes will conserve a reference to your 'this', which will keep it alive. If you are repeatedly creating and 'destroying' whatever is listening to the event, you will find that they aren't being collected by the garbage collector.
If this is a problem, you can go the route suggested in the answers, conserving a reference to the handler, which you must create first.
Another solution is to use weak references to create an event handler which will allow the subscriber to be collected if there are not other references. I've explored this solution in this question and answer.

EventHandlers and Anonymous Delegates / Lambda Expressions

I'm hoping to clear some things up with anonymous delegates and lambda expressions being used to create a method for event handlers in C#, for myself at least.
Suppose we have an event that adds either an anonymous delegate or a lambda expression (for you lucky crowds that can use newer versions of .NET).
SomeClass.SomeEvent += delegate(object o, EventArg e) { /* do something */ };
I have read that people in the past have forgotten about events that still have handlers which prevent the class from being garbage collected. How would one go about removing the added handler without just setting SomeEvent to null within the class. Wouldn't the following be an entirely new handler?
SomeClass.SomeEvent -= delegate(object o, EventArg e) { /* do something */ };
I could see storing the anonymous delegate or lambda expression in a variable. But that, to me at least, seems to defeat the entire purpose of being able to simply and succinctly add an event handler.
SomeEventDelegate handler = new SomeEventDelegate(delegate(object o, EventArg e) { /* do something */ });
SomeClass.SomeEvent += handler;
// ... stuff
SomeClass.SomeEvent -= handler;
Again, I understand that you could just do...
public override Dispose(bool disposing)
{
_someEvent = null;
this.Dispose();
}
But I'm more interesting with just removing the dynamically created method from the event. Hopefully someone can shed some light onto this for me. Thanks!
If object X has an event handler whose target is object Y, then object X being alive means that object Y can't be garbage collected. It doesn't stop object X from being garbage collected.
Normally when something is disposed, it will become garbage pretty soon anyway, which means you don't have a problem.
The problem with events and GC is if you forget to remove a subscribed handler from a different object - i.e. you have a listener which is disposed, but will never be garbage collected because there's still a reference to it from the event in a different object.
I think the problem is you seem to be proceeding from the assumption that having a delegate assigned to an object's event prevents it from being GCed.
This as a simple statement is not true.
With that said the perceived problem disappears.
Initially in garbage collection everything is garbage. The GC runs through every thing currently available globally and on each stack and from these those other objects that they are referencing and so on, marking each as not garbage.
How would such a graphing process manage to arrive at this object?
You can't.
Just like you can't create anonymous type outside of its scope (except for some compiler tricks).
That's why it's called anonymous.
You have to save a reference somewhere... or use reflection.

Categories

Resources