2009-11-27 8 views
22

Io di solito uso il codice come questo:È richiesto SqlCommand.Dispose() se SqlConnection associato verrà eliminato?

using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString)) 
{ 
    var command = connection.CreateCommand(); 
    command.CommandText = "..."; 
    connection.Open(); 
    command.ExecuteNonQuery(); 
} 

La mia command smaltiti automaticamente? O no e devo avvolgere nel blocco using? È necessario smaltire SqlCommand?

+0

È troppo male Microsoft ha creato SqlCommand a Component. Se avessero davvero bisogno di un componente per il supporto del designer, avrebbe potuto essere un wrapper su un SqlCommand leggero che non implementasse IDisposable. –

risposta

22

solo fare questo:

using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString)) 
using(var command = connection.CreateCommand()) 
{ 
    command.CommandText = "..."; 
    connection.Open(); 
    command.ExecuteNonQuery(); 
} 

Non chiamando Dispose sul comando non farà nulla troppo male. Tuttavia, se chiami Dispose su di esso sarà supress the call to the finalizer, rendendo la chiamata smaltire un miglioramento delle prestazioni.

+11

"Non chiamare dispose sul comando non farà niente di male." Vero, ma non ci si abitua; è vero solo per 'SqlCommand's. D'altra parte, non disponendo di un 'SqlCeCommand', ad esempio, * farà * il tuo dispositivo mobile esaurirà la memoria abbastanza velocemente. (Appena stato lì, fatto ...) – Heinzi

+2

'Dispose' non sopprime la finalizzazione dal momento che il costruttore lo fa. –

8

La politica più sicura è quella di chiamare sempre Dispose() su un oggetto se implementa IDisposable, in modo esplicito o tramite un blocco di utilizzo. Ci possono essere casi in cui non è richiesto, ma chiamarlo comunque non dovrebbe mai causare problemi (se la classe è scritta correttamente). Inoltre, non si sa mai quando un'implementazione può cambiare, il che significa che, laddove la chiamata non era richiesta in precedenza, è ora definitivamente richiesta.

Nell'esempio che hai fornito, puoi aggiungere un ulteriore blocco interno usando il comando, oltre a mantenere il blocco esterno usando per la connessione.

+2

Sì, la politica più sicura è quella di disporre sempre di oggetti monouso, in particolare se * l'hai * creato! Ad esempio, non è una buona idea scrivere un metodo che accetta uno stream e disporre lo stream all'interno di quel metodo. Un altro avvertimento è che non si può sempre disporre tramite l'istruzione using con impunità. I proxy WCF sono l'unico esempio pratico che conosco. Se qualcosa va storto al remoto e si ottiene un'eccezione il canale si chiude e Dispose lancia quindi una nuova eccezione, sostituendo l'eccezione originale, che può essere un problema serio. –

+1

un altro motivo per non usare WCF! grazie per il suggerimento ;-) –

1

È possibile trovare questo tipo di materiale utilizzando Reflector.

Ho fatto un piccolo scavo (ti suggerirei di scavare te stesso per essere completamente sicuro del resto di questo anche se non ho provato così tanto) e sembra che quando si uccide una connessione non c'è smaltimento di qualsiasi bambino associato a quella connessione. Inoltre, in realtà non sembra che lo smaltimento di un comando lo faccia davvero molto. Imposta un campo su null, si stacca da un contenitore (ciò potrebbe impedire una perdita di memoria gestita) e genera un evento (questo potrebbe essere importante ma non riesco a vedere chi sta ascoltando questo evento).

In entrambi i casi è buona norma utilizzare questo materiale in un blocco di utilizzo o assicurarsi di smaltirlo utilizzando un modello di smaltimento nell'oggetto che contiene la connessione (se si intende trattenere il comando per un po ').

4

Sì, dovresti, anche se attualmente l'implementazione non sta facendo molto, non sai come verrà modificata in futuro (nuove versioni di framework ad esempio). In generale, è necessario disporre di tutti gli oggetti che implementano IDisposable in modo sicuro.

Tuttavia, se l'operazione è differita e non si controlla l'intera gamma (per esempio quando si lavora asynchroneously, o quando si restituisce un SqlDataReader o giù di lì), è possibile impostare il CommandBehavior a CloseConnection in modo che non appena il lettore è fatto, la connessione è correttamente chiusa/smaltita per te.

2

In pratica, è possibile saltare Dispose. Non libera risorse. Non sopprime nemmeno la finalizzazione dal momento che il costruttore lo fa.

In teoria, Microsoft potrebbe cambiare l'implementazione per prendere in mano una risorsa non gestita, ma mi auguro che sarebbero usciti con un'API che si sbarazzasse della classe base molto prima che lo facessero.