Me lo chiedo perché la vedo raramente usata nei forum e nel codice che mi capita di guardare e mi domando il perché, visto che è così comoda da usare. Beh il mio consiglio è: qualsiasi oggetto create, se implementa IDisposable, usate sempre la using.
Per i seguenti motivi:
- Occorre sempre chiudere risorse unmanaged in modo esplicito e il prima possibile. Se si demanda il lavoro al Garbage Collector il Dispose verrà effettuato sfruttando la Finalize e l'oggetto resterà nell'heap per un giro di GC in più e rischiamo inoltre che l'oggetto diventi più forte come generation e non venga più rimosso;
- Anche se l'oggetto non fa uso risorse unmanaged, la Dispose va chiamata lo stesso. Primo perché non possiamo mai sapere se in una futura versione l'oggetto utilizzerà tali risorse e secondo perché chiamando Dispose, se la classe è scritta bene, viene chiamato GC.SuppressFinalize(this) così da togliere l'oggetto dalla finalization list, il GC lo rimuoverà dall'heap e il problema indicato nel primo punto non si verificherà.
Se scriviamo delle nostre classi che fanno uso di risorse unmanaged o di classi che a loro volta ne fanno uso, vi consiglio di ereditare da System.ComponentModel.Component. Implementa già il pattern Dispose, con l'interfaccia IDisposable, il metodo Finalize e mettendo a disposizione un metodo virtuale Dispose(bool disposing). Una tipica classe è così:
public class MiaClasse : System.ComponentModel.Component
{
private bool disposed;
public void MioMetodo()
{
if (disposed)
throw new ObjectDisposedException(base.GetType().Name);
}
protected override void Dispose(bool disposing)
{
if (disposing) {
risorsaunmanaged.Dispose();
}
risorsaunmanaged = null;
this.disposed = true;
base.Dispose(disposing);
}
}L'uso della variabile disposed è "facoltaltiva", ma utile se vogliamo lanciare un eccezione nel caso qualcuno chiami un nostro metodo quando ne ha già chiamato il Dispose.
Quindi insomma, usiamo la using che non vi costa e scriviamo le classi nel modo giusto ;-)
padovaboy ha scritto:
A parte che il mio mito (detto anche "il faro") mi rimane il nostromo del gruppo...questa volta facevo riferimento a te casati ;)
Uh! Che onore. Cmq Marco resta di un altro pianeta!
In effetti poi basta usare entrambe le strutture: incapsuli l'using in un try
Esatto: semplice semplice.
E ora non hai più scuse: sempre "using" quando tratti oggetti che implementano IDisposable!
padovaboy ha scritto:
Cmq mi sono guardato un pò in giro e in effetti è piuttosto semplice.
Il mio dubbio iniziale era che se l'using era un semplice try finally, n'do me lo mettevo il catch? (poi ammetto per rincxxxmnto mattutino ho pensato che la struttura using non permettesse "la fuoriuscita" dell'exception...)
In effetti poi basta usare entrambe le strutture: incapsuli l'using in un try, il che non è obbligatorio, ma si sa che con le risorse non c'è da scherzare :P
Ocio che il costrutto try/catch/finally è sconsigliato. Meglio fare un try/finally all'interno di un try/catch, questo perché è meglio prima di tutto liberare da subito le risorse, e poi catturare l'eccezione, loggare, mostrare all'utente ecc.
Ricciolo ha scritto:
costrutto try/catch/finally è sconsigliato. Meglio fare un try/finally all'interno di un try/catch
Assolutamente. Però con "using" il try/finally non serve praticamente più, o meglio: lo scrive il framework al posto nostro
questo presuppone accendere il cervello. tanta gente quando sviluppa, invece, lo spegne. non so, anzichè avere più attenzione, spesso quando si scrive codice si tende a distrarsi con musica, messenger, colleghi. vero eh?
Daniele Bochicchio ha scritto:
spesso quando si scrive codice si tende a distrarsi con musica, messenger, colleghi. vero eh?
LOL
Cmq è vero...
Grazie c/ricciolo
Quindi insomma, usiamo la using che non vi costa e scriviamo le classi nel
modo giusto ;-)
e parlando del mondo web, finalmente molti dev troveranno sistemisti felici di trovarsi applicazioni che non succhiano risorse inutilmente e soprattutto che le rilasciano ad caum
Concordo pienamente.
Supponiamo di dover eseguire una stored procedure per la lettura dei dati (ad es. "spGetItem"). Il code snippet per effettuare questa operazione è il seguente:
SqlConnection cn = null;
SqlCommand cmd = null;
SqlDataReader dr = null;
try
{
cn.Open();
cmd = new SqlCommand("spGetItem", cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Id", id);
dr = cmd.ExecuteReader();
while (dr.Read())
{
// do something with DataReader
}
}
finally
{
if (dr != null)
{
dr.Close();
dr.Dispose();
}
if (cmd != null)
cmd.Dispose();
if (cn != null)
{
cn.Close();
cn.Dispose();
}
}
In questo modo tutti gli oggetti in uso (connection, command e datareader) vengono chiusi e "disposati" in modo corretto nello statement finally.
Questo codice però è piuttosto gravoso da scrivere e mantenere (senza contare che anche le singole distruzioni degli oggetti dovrebbero stare dentro un blocco try...catch) e potrebbe facilmente indurre ad errori.
Usando il fantastico statement "using" il codice di cui sopra si riduce a:
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
cn.Open();
using (SqlCommand cmd = new SqlCommand("spGetItem", cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Id", id);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
// do something with DataReader
}
}
}
}
Decisamente più compatto, meno oneroso da scrivere e anche più sicuro.
Spero di aver convinto anche i più scettici
HTH
"Defines a scope, outside of which an object or objects will be disposed."
Opporca! Non lo sapevo mica :P
Grazie per la scoperta...ma se volessi comunque mettere un bel try catch dentro all'using?
Riprendendo l'esempio del "mitico" verrebbe una cosa del genere:?
Come si impatta questa struttura sul try catch?
Grazie a tutti!
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
try {
cn.Open();
using (SqlCommand cmd = new SqlCommand("spGetItem", cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Id", id);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
// do something with DataReader
}
}
}
} Catch (Exception ex){
// log....
}
}
buahahhaah, questo tuo esempio mi ricorda un sacco di cose!!!
padovaboy ha scritto:
Riprendendo l'esempio del "mitico"
Come si impatta questa struttura sul try catch?
In compilazione lo statement using viene sostituito da un blocco "try...finally..."
Ad esempio:
using (StreamReader reader = new StreamReader(@"C:\My Files\test.txt"))
{
string text = reader.ReadToEnd();
}
[code]
Equivale *esattamente* a:
[code]
StreamReader reader = new StreamReader(@"C:\My Files\test.txt");
try
{
string text = reader.ReadToEnd();
}
finally
{
reader.Dispose();
}
Infatti il codice MSIL del codice che usa lo statement "using" è:
// Code size 31 (0x1f)
.maxstack 2
.locals init ([0] class [mscorlib]System.IO.StreamReader reader,[1] string text)
IL_0000: ldstr "C:\\My Files\\test.txt"
IL_0005: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_000a: stloc.0
.try
{
IL_000b: ldloc.0
IL_000c: callvirt instance string [mscorlib]System.IO.TextReader::ReadToEnd()
IL_0011: stloc.1
IL_0012: leave.s IL_001e
} // end .try
finally
{
IL_0014: ldloc.0
IL_0015: brfalse.s IL_001d
IL_0017: ldloc.0
IL_0018: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_001d: endfinally
} // end handler
IL_001e: ret
(source: Why use using?)
Detto questo nulla ti vieta di racchiudere tutto il corpo del metodo (o una sua parte) in un blocco try...catch esterno, ad esempio, come nel tuo esempio, per gestire il log delle eccezioni.
Il vantaggio è che non sei costretto a gestire eventuali eccezioni per ogni oggetto al fine di assicurarne la distruzione (rischiando di dimenticartene qualcuno!) ma solo le eccezioni significative per il tuo metodo. Un bel risparmio, no?
imperugo ha scritto:
buahahhaah, questo tuo esempio mi ricorda un sacco di cose!!!
Tipo?
Segretissimo (chiedi a dTipo?
buahahah
imperugo ha scritto:
effettuare il dispose dei reader è un optional!!!
buahahah
Già, non è detto che una voglia un'applicazione funzionante, per cui puoi anche evitarti le dispose...
Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.





Stampa
Download

10annidi.ASPItalia.com: iscriviti alla competizione e vinci fantastici premi ogni mese!

A parte che il mio mito (detto anche "il faro") mi rimane il nostromo del gruppo...questa volta facevo riferimento a te casati ;)
Cmq mi sono guardato un pò in giro e in effetti è piuttosto semplice.
Il mio dubbio iniziale era che se l'using era un semplice try finally, n'do me lo mettevo il catch? (poi ammetto per rincxxxmnto mattutino ho pensato che la struttura using non permettesse "la fuoriuscita" dell'exception...)
In effetti poi basta usare entrambe le strutture: incapsuli l'using in un try, il che non è obbligatorio, ma si sa che con le risorse non c'è da scherzare :P
Grazie intanto a tutti ^_^
Continua »»» | Rispondi »»»