SqlCommand.Dispose () è richiesto se verrà eliminato SqlConnection associato?
-
05-07-2019 - |
Domanda
Di solito uso un codice come questo:
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
var command = connection.CreateCommand();
command.CommandText = "...";
connection.Open();
command.ExecuteNonQuery();
}
Il mio comando
verrà automaticamente eliminato? Oppure no e devo inserirlo nel blocco usando
? È necessario disporre di SqlCommand
?
Soluzione
Basta fare questo:
using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
using(var command = connection.CreateCommand())
{
command.CommandText = "...";
connection.Open();
command.ExecuteNonQuery();
}
Non chiamare dispose sul comando non farà nulla di male. Tuttavia, chiamando Dispose su di esso sopprime la chiamata al finalizzatore , facendo sì che la chiamata disponga di un miglioramento delle prestazioni.
Altri suggerimenti
La politica più sicura è chiamare sempre Dispose ()
su un oggetto se implementa IDisposable
, esplicitamente o tramite un blocco using. 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 precedentemente richiesta, ora è sicuramente richiesta.
Nell'esempio che hai fornito, puoi aggiungere un blocco using interno extra per il comando, oltre a mantenere il blocco using esterno per la connessione.
Sì, dovresti, anche se l'implementazione non sta facendo molto, non sai come sarà cambiata in futuro (ad esempio versioni più recenti del framework). In generale, dovresti disporre tutti gli oggetti che implementano IDisposable
per essere al sicuro.
Tuttavia, se l'operazione è differita e non si controlla l'intero ambito (ad esempio quando si lavora in modo asincrono o quando si restituisce un SqlDataReader
o giù di lì), è possibile impostare il CommandBehavior
in CloseConnection
in modo che, non appena il lettore ha terminato, la connessione sia correttamente chiusa / disposta per te.
Puoi scoprire questo tipo di cose usando Reflector o dotPeek o < a href = "https://referencesource.microsoft.com/" rel = "nofollow noreferrer"> https://referencesource.microsoft.com/ .
Ho avuto un piccolo scavo (ti suggerirei di scavare te stesso per essere completamente sicuro del resto, anche se non ci ho provato tanto) e sembra che quando uccidi una connessione non ci sia tutti i bambini associati a tale connessione. Inoltre, in realtà non sembra che l'eliminazione di un comando faccia davvero tanto. Imposta un campo su null, si stacca da un contenitore (questo 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 questa roba in un blocco using o assicurarsi di eliminarla usando un modello dispose nell'oggetto che contiene la connessione (se si intende mantenere il comando per un po ').
In pratica, puoi saltare Dispose
. Non libera alcuna risorsa. Non sopprime nemmeno la finalizzazione poiché Il costruttore di comandi SQLC lo fa .
In teoria, Microsoft potrebbe cambiare l'implementazione per contenere una risorsa non gestita, ma spero che escano con un'API che si sbarazzi della classe base Component
molto prima che lo facciano che.
Secondo me, chiamare Dispose
sia per SqlConnection
sia per SqlCommand
è una buona pratica, usare il codice sotto
using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
try{
using(var command = connection.CreateCommand())
{
command.CommandText = "...";
connection.Open();
command.ExecuteNonQuery();
}
}
catch(Exception ex){ //Log exception according to your own way
throw;
}
finally{
command.Dispose();
connection.Close();
connection.Dispose();
}