2011-10-18 10 views
5

Sono a conoscenza della tecnica per gestire IDisposable in modo tradizionale. Di ', in OnStop() di servizio di Windows chiudo messaggio coda di cliente:Smaltimento impostando su null?

 if (client != null) 
     { 
      client.Dispose(); 
     } 

Per la prima volta oggi ho visto un ragazzo a farlo in questo modo:

 using (client) 
     { 
      client = null; 
     } 

che cosa è esattamente accadendo all'interno del suo "usare" o ha a disposizione correttamente?

risposta

4

Il codice del collega using funzionerà, ma è discutibilmente eccessivo;

using(client) { 
    client = null; 
} 

è essenzialmente:

{ // scope here to denote that 'tmp' is not defined outside this scope 
    var tmp = client; 
    try { 
     client = null; 
    } finally { 
     if(tmp != null) tmp.Dispose(); 
    } 
} 

(non del tutto che in tutti i casi, in quanto vi sono di valore tipi e implementazione dell'interfaccia esplicita a cui pensare).

Personalmente, dovrei semplicemente usare using per l'intera cosa, ove possibile (cioè nel codice che inizialmente alloca il client).

Una volta potrei usare questo è un pigro:

using(client as IDisposable) { client = null; } // dispose if needed 

cioè client è qualcosa al di fuori del mio controllo, e non sono sicuro se implementa IDisposable o no, ma se lo fa, ho bisogno di rilascialo.

+0

BTW, una cosa penso che migliorerebbe l'usabilità di "using" sarebbe la possibilità di impostare esplicitamente la "variabile shadow" su null, in modo che l'oggetto non venisse smaltito, oppure avere una versione di "using" che disporrebbe solo in caso di colpa. Un costruttore, ad esempio, potrebbe quindi "utilizzare" i campi dell'oggetto da costruire, e quindi decidere di "mantenerli" appena prima che ritornasse. È possibile utilizzare i blocchi try/finally invece di "using", ma sono più prolissi e meno chiari. – supercat

+0

@supercat IMO che lo scenario è già piuttosto complesso - meglio essere espliciti al riguardo e capire cosa sta succedendo (cioè sono contento di 'try' /' finally' there) –

+0

Ho appena guardato di nuovo il codice e penso Ho capito lo scopo - se "client" è un campo o una proprietà, la sua vita potrebbe probabilmente non essere confinata in un blocco "using". In alcuni casi, potrebbe essere necessario eliminare un campo o una proprietà che contiene un riferimento all'oggetto prima di chiamare Smaltisci su di esso. Il codice "using" mostrato qui sarebbe più conciso rispetto alla creazione esplicita di una variabile temporanea, anche se un approccio ancora migliore sarebbe utilizzare una routine "Zap" per tale scopo. – supercat

3

Uscendo dal

using (client) 
{ 
} 

client.Dispose() si chiama automaticamente per voi.
client = null dovrebbe essere chiamato da quel codice a mio parere.
Ricordare che per utilizzare using(object) l'oggetto deve implementare l'interfaccia IDisposable.

+2

Perché downvote? Ho detto qualcosa di sbagliato, per favore spiega così posso correggere o cancellare la mia risposta ... – Marco

+0

No, non c'è niente di particolarmente sbagliato; ci sono stati alcuni downvotes dispari espressi da un singolo utente; nessun legame forte con gli utenti coinvolti in questo thread. Solo ... strano, davvero. –

+0

Grazie a @MarcGravell, solo per capire e (eventualmente) imparare qualcosa di nuovo ... – Marco

6

L'istruzione using(){} prende una copia della variabile di riferimento in modo che questa assegnazione con null non sia efficace.

+0

ma anche innocuo (non interferisce con la chiamata da smaltire) – Martijn

+0

D'accordo nel secondo caso è necessario copiare nuovamente il puntatore. Non ha senso rendere Dispose implicito all'interno di se stesso. In ogni caso è necessario anche un controllo nullo per evitare l'eccezione di null ref quando il rientri si dispone. –

+1

@Martijn - innocuo? di solito ma non se si desidera rimandare il Dispose di 'client'. Raro ma possibile. –

0

Per me non sembra affatto efficace. Poiché il client è impostato su null, l'utilizzo non ha più nulla a cui fare riferimento, anche se l'oggetto reale è ancora in memoria, semplicemente non referenziato da alcuna variabile (sarà più tardi raccolto, ma qual è il punto di utilizzo?).

0

Se l'ambito del "client" si estende al di fuori del blocco "using", come sembrerebbe, il codice come scritto garantirà che il "client" venga eliminato prima che il controllo lasci il blocco "using" e il riferimento a l'oggetto "client" appena defunto sarà distrutto. Annullare il riferimento ad esso può essere importante se si tratta di un campo, e potrebbe essere fondamentale se si tratta di una proprietà che allega eventi.

La mia ipotesi sarebbe che "client" è un campo o una proprietà e che l'autore del codice "using" pensava che fosse più conciso della versione data da Marc Gravell. Concederei all'autore che il codice è conciso, ma suggerirei che sarebbe ancora più conciso e più chiaro definire una routine generica "Zap" che accetta un identificativo mediante il riferimento, utilizza Interlocked.Exchange per leggerlo e annullarlo e lo smaltisce se non fosse nullo.In tal caso, la dichiarazione "utilizzando" sarebbe sostituito con:

 
    Zap(ref client); 

che ha il vantaggio di essere più conciso, mentre quasi certamente di essere più chiaro.