5

If I create a lambda callback such as this:

var someInstance = new SomeObject(); someInstance.Finished += (obj, args) => { // Do something // Deregister here }; someInstance.DoAction(); 

How could I deregister the callback as part of the actual handler code? This pattern would be ideal as I could ensure it is released as soon as possible.

I've seen similar questions but not one where this type of example is directly addressed.

10
  • Very similar to stackoverflow.com/questions/183367/… Commented Apr 26, 2011 at 22:51
  • Similar yes, but what I am looking for is a way to deregister within the actual handler and not in some other scope. Commented Apr 26, 2011 at 22:51
  • 1
    You might find this question I asked interesting: stackoverflow.com/questions/5623658/… Commented Apr 26, 2011 at 23:00
  • Hello Nissan Fan There are several things you can do it some are better then others but the real issue is thread management, obviously if you know the calling code is not multi-threaded but if it is you should make the code making this kinda call is thread safe to ensure there is no clashes. Delegates are and threads tend to need careful considerations but of course there is no need to over think it. Commented Apr 26, 2011 at 23:09
  • This may lead to a follow-up which involves mutexes. It just seems like .NET could benefit from having a way to self-dereference these lambdas. Commented Apr 26, 2011 at 23:12

5 Answers 5

6

With something like,

var someInstance = new SomeObject(); EventHandler myDelegate = null; myDelegate = (obj, args) => { // Do something // Deregister here someInstance.Finished -= myDelegate; }; someInstance.Finished += myDelegate; someInstance.DoAction(); 
Sign up to request clarification or add additional context in comments.

4 Comments

delegate myDelegate = null; does not compile.
Use EventHandler myDelegate = null; instead, that should work.
Yup, it looks a lot like mine now. ;-)
Except mine looks like the OP's.
5

You can use MethodInfo.GetCurrentMethod inside your lambda to retrieve the MethodInfo of the lambda.

With the MethodInfo, you can use Delegate.CreateDelegate to get the properly typed delegate representing your lambda.

And with the delegate, you can unregister the lambda, all without storing your function in a variable or making it a named method.

class MyClass { public event EventHandler TheEvent; void TestIt() { TheEvent += (sender, eventargs) => { Console.WriteLine("Handled!"); // do something in the handler // get a delegate representing this anonymous function we are in var fn = (EventHandler)Delegate.CreateDelegate( typeof(EventHandler), sender, (MethodInfo)MethodInfo.GetCurrentMethod()); // unregister this lambda when it is run TheEvent -= fn; }; // first time around this will output a line to the console TheEvent(this, EventArgs.Empty); // second time around there are no handlers attached and it will throw a NullReferenceException TheEvent(this, EventArgs.Empty); } } 

2 Comments

I really like this code example. It's a shame that MS doesn't expand the C# language to include a release event keyword that automatically unbinds the event handler for the currently scoped code.
Hrm .. I'm not seeing an obvious way to put the implementation in its own method either due to the limitations against using delegate types as generic type constraints.
5

If you want the ability to unregister, then it's best to define your lambda as an Action, so that you can write:

someInstance.Finished += MyCustomAction; 

and later

someInstance.Finished -= MyCustomAction; 

Comments

1

If you want to remove the event handler afterwards, you should use a named function:

 someInstance.Finished += HandleFinished; //... void HandleFinished(object sender, EventArgs args) { someInstance.Finished -= HandleFinished; } 

2 Comments

So there is no way to deregister the callback from within the actual handler as part of a clean-up process?
@Nissan Fan: I believe it is possible to get a delegate from a MethodBase (i.e., MethodInfo.GetCurrentMethod), but I don't have the time at this moment to find out exactly how ... if I remember I'll come back to it but I would say don't give up too quickly.
1

This appears to work:

EventHandler handler = null; handler = new EventHandler((sender, e) => SomethingHappened -= handler); SomethingHappened += handler; 

Just be sure you don't assign handler to any other value, as the closure is tied to that variable. This is what Resharper complains of as an "Access to Modified Closure."

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.