Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - anonymous functions and event handlers

Tags:

I have the following code:

public List<IWFResourceInstance> FindStepsByType(IWFResource res)   {       List<IWFResourceInstance> retval = new List<IWFResourceInstance>();       this.FoundStep += delegate(object sender, WalkerStepEventArgs e)                          {                            if (e.Step.ResourceType == res) retval.Add(e.Step);                          };       this.Start();       return retval; }   

Notice how I register my event member (FoundStep) to local in-place anonymous function.

My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)

I hope my question was clear.

like image 204
Adi Barda Avatar asked Sep 07 '09 13:09

Adi Barda


2 Answers

Your code has a few problems (some you and others have identified):

  • The anonymous delegate cannot be removed from the event as coded.
  • The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
  • Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
  • The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.

To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):

  public List<IWFResourceInstance> FindStepsByType(IWFResource res)   {      List<IWFResourceInstance> retval = new List<IWFResourceInstance>();      EventHandler<WalkerStepEventArgs> handler = (sender, e) =>      {         if (e.Step.ResourceType == res) retval.Add(e.Step);      };       this.FoundStep += handler;       try      {         this.Start();      }      finally      {         this.FoundStep -= handler;      }       return retval;   } 

With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:

    public List<IWFResourceInstance> FindStepsByType(IWFResource res)     {         var retval = new List<IWFResourceInstance>();          void Handler(object sender, WalkerStepEventArgs e)         {             if (e.Step.ResourceType == res) retval.Add(e.Step);         }          FoundStep += Handler;          try         {             this.Start();         }         finally         {             FoundStep -= Handler;         }          return retval;     } 
like image 131
Kit Avatar answered Sep 21 '22 18:09

Kit


Below is approach about how unsubscribe event in anonymous method:

DispatcherTimer _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(1000); EventHandler handler = null;  int i = 0;  _timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev) {     i++;     if(i==10)         _timer.Tick -= handler; });  _timer.Start(); 
like image 21
Amit Avatar answered Sep 18 '22 18:09

Amit