2015-10-11 11 views
5

Perché questa dichiarazione + assegnazione causano un errore:uso di variabile locale non assegnata quando si crea una funzione anonima chiusura su se stesso

// Use of unassigned local variable 'handler'. 
SessionEndingEventHandler handler = (sender, e) => { isShuttingDown = true; SystemEvents.SessionEnding -= handler; }; 

mentre questo non:

SessionEndingEventHandler handler = null; 
handler = (sender, e) => { isShuttingDown = true; SystemEvents.SessionEnding -= handler; }; 

In è intuitivo che il la prima affermazione dovrebbe causare un errore, ma non immediatamente chiarisce perché la seconda non lo è.

Inoltre, come è possibile sapere se l'evento SystemEvents.SessionEnding è stato effettivamente annullato dopo la chiamata a handler(null, null)? GetInvocationList funziona solo con i delegati.

SystemEvents.SessionEnding += handler; 
handler(null, null); 
+1

La prima istruzione è più equivalente a 'Gestore SessionEndingEventHandler;', mentre nella seconda istruzione lo si assegna a null. La sua non assegnata fino a quando il lambda è completamente costruito. Vedi http://stackoverflow.com/questions/1362204/how-to-remove-a-lambda-event-handler –

risposta

9

E 'per lo stesso motivo che ci si aspetta che questo venga meno

int i = 1 - i; 

Il lato destro della dichiarazione viene valutata prima della cessione, e nel momento in cui esso viene valutato, la variabile non è stata ancora assegnata.

Nel caso in cui si pensa lambda/delegati le cose cambiano, si consideri la seguente dichiarazione:

int i = ((Action)() => 1 - i)(); 

Perché si sta creando la lambda prima i è assegnato, è possibile che i potrebbe essere utilizzato prima di qualsiasi valore è stato assegnato ad esso. Il fatto che non ti aspetti che ciò accada nel tuo caso non cambia le cose dal punto di vista del compilatore - devi assegnare esplicitamente un valore alla variabile prima che venga utilizzata. Se si tratta di un valore nullo, almeno il compilatore sa che stai considerando la possibilità che diventi nullo quando ci arrivi.

Per quanto riguarda la tua domanda finale, un SessionEndingEventHandlerè un delegato. Quindi funzionerebbe bene:

var unsubscribed = SystemEvents.SessionEnding == null || 
    !SystemEvents.SessionEnding.GetInvocationList().Contains(handler); 
Problemi correlati