views:

75

answers:

1

I'm wondering what the 'best practice' is, when asking an event handler to unsubscribe its self after firing once.

For context, this is my situation. A user is logged in, and is in a ready state to handle work items. They receive a work item, process it, then go back to ready again. At this point, they may want to say they're not available for more work items, but one is sent to them anyway. What I want to be able to do, is allow the user to 'queue' a 'I'm not available' as soon as that operation becomes possible.

public event SomeHandler StateChanged = delegate {};

public void QueueNotAvailable() 
{
    StateChanged += (s,e) => {
                                 if (e.CanGoNotAvailable) { 
                                     someObject.NotAvailable();
                                     StateChanged -= {thishandler};
                                 }
                             }
}

For my purposes, if a separate thread happens to fire off the events and this particular handler runs twice, it is not a problem. Requesting the same function very close together is acceptable. I just don't want it firing every single time the operation is allowed.

+7  A: 

You can save an instance of the delegate before subscribing to the event:

public void QueueNotAvailable() 
{
    SomeHandler handler = null;
    handler = (s,e) {
        // ...
        StateChanged -= handler;
    };
    StateChanged += handler;
}

I believe this should do it... I had to put the initial handler = null in there otherwise you get 'Use of unassigned local variable' compilation errors, but I think it's actually benign.

Dean Harding
That's pretty cool that it can reference itself. Surely what you're saying in there is "StateChanged -= null" ? You'd also have to have the handler stored in a class-level member as I assume the OP wants to change the StateChanged/handler state each handler execution.
Graphain
@Graphain: I meant on line 3, I have `SomeHandler handler = null;` - I had to put that on a line on it's own (rather than assigning it directly to the anonymous delegate) because I got a compiler error otherwise. It doesn't need to be a class-level member, since the closure created by the anonymous delegate will just do it's magic...
Dean Harding
@codeka, i realise that, but i mean on line 5 (ignoring comment), handler would exist as null when it creates it. I guess we're lucky in that the code isn't executed until handler is bound so it's a non issue. Like I mean "a=null" then "a=(a+1)" is actually "(a=(null+1)"
Graphain
@Graphain: Right, but I think the compiler is wrong to give the "use of unassigned local variable" in this particular case, because it's physically impossible (AFAICT) to call the anonymous delegate without first assigning it to the variable. So it's not possible that `handler` will ever be unassigned inside the delegate body. Anyway, it's only one extra line so not a big deal :)
Dean Harding
Fantastic! I was thinking that I'd have to store the SomeHandler reference in a higher scope to get it to work, and 15 or so similar functions would look messy. Forgot about the closure. Thanks
Josh Smeaton