-1

I have a list of objects and I would like to subscribe/unsubscribe each of them to an event (via a delegate because I need to pass extra params to the methods). So I have something like this:

 public void MonitoringCtrl(bool monitoringOn)
    {
        foreach (var mh in monHandlers)
        {
            evHandler = (sender, e) => OnNotification(sender, e, mh);

            if (monitoringOn)
            {
                //subscribe to event
                mh.monitoredItem.Notification += evHandler;
            }
            else
            {
                //unsubscribe
                mh.monitoredItem.Notification -= evHandler;
            }
        }

        //do other stuff
    }

This works when subscribing, but doesn't work when unsubscribing, presumably because I re-declare the evHandler inside the foreach. How can I save the reference to the evHandler?

  • 1
    You could turn your lambda into a real method. Or store your lamda as a class member. – itsme86 Jul 21 '20 at 17:58
  • There are already lots of Q&A on the site discussing this general scenario. You won't be able to follow the named method approach, because you rely on the captured value of `mh`. So you will have to use one of the alternatives, such as saving the delegate instance somewhere, or retrieving the `mh` value from the `sender` (e.g. if you have some mapping from `monitoredItem` back to the `mh` object that holds that reference). Actually, if you can do the latter, then a named method _will_ work. – Peter Duniho Jul 21 '20 at 18:57

1 Answers1

-1

This is because with the second call to MonitoringCtrl() (when you pass false to unsubscribe), a new event handler is created. But that new instance does not unsubscribe an event handler instance that was attached before.

You don't need to create a new event handler for each element in the loop and you must not create new ones to unsubsribe. You could keep one single event handler for all occurances as member variable. But is even easier to do this by binding to a method like this:

public void MonitoringCtrl(bool monitoringOn)
{
    foreach (var mh in monHandlers)
    {
        if (monitoringOn)
        {
            //subscribe to event
            mh.monitoredItem.Notification += HandleNotification;
        }
        else
        {
            //unsubscribe
            mh.monitoredItem.Notification -= HandleNotification;
        }
    }

    //do other stuff
}

private void HandleNotification(object sender, EventArgs args)
{
    //do event stuff
}

Update I just saw that you need to use delegates to caputre additional arguments

You could use local functions to capture properties of the parent method but in your case, you would need to capture the loop variable. That won't work so I'd try to find a way to get the mh out of the sender because it seems to be related. Is the sender the monitoredItem and it's parent the monitorHandler you want to pass with the lambda (mh)?

Waescher
  • 5,361
  • 3
  • 34
  • 51