Perché non usate lo statement using?

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 ;-)

Nella stessa categoria

Commenti
PadovaBoy scrive:
Perché non usate lo statement using?

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 ^_^
10/12/2007 ore 13.03 | 3 risposte
m.casati scrive:
RE: Perché non usate lo statement using?

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!
10/12/2007 ore 17.10
Ricciolo scrive:
RE: Perché non usate lo statement using?

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.
10/12/2007 ore 18.44 | 1 risposta
m.casati scrive:
RE: Perché non usate lo statement using?

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
11/12/2007 ore 9.07
Daniele Bochicchio scrive:
Re: Perché non usate lo statement using?

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?
07/12/2007 ore 15.43 | 1 risposta
m.casati scrive:
Re: Perché non usate lo statement using?

Daniele Bochicchio ha scritto:
spesso quando si scrive codice si tende a distrarsi con musica, messenger, colleghi. vero eh?


LOL
Cmq è vero...
10/12/2007 ore 9.52
ITHost scrive:
Re: Perché non usate lo statement using?

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
07/12/2007 ore 1.05 | 1 risposta
Ricciolo scrive:
07/12/2007 ore 8.38
m.casati scrive:
Perché non usate lo statement using?

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
06/12/2007 ore 15.32 | 6 risposte
PadovaBoy scrive:
RE: Perché non usate lo statement using?

"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!

[CODE]

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....
   }
}
[/CODE]
07/12/2007 ore 10.04 | 1 risposta
imperugo scrive:
RE: Perché non usate lo statement using?

buahahhaah, questo tuo esempio mi ricorda un sacco di cose!!!
10/12/2007 ore 10.09 | 1 risposta
m.casati scrive:
RE: Perché non usate lo statement using?

padovaboy ha scritto:
Riprendendo l'esempio del "mitico"

Chi è il "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();
}


Equivale *esattamente* a:


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?
10/12/2007 ore 10.15
m.casati scrive:
RE: Perché non usate lo statement using?

imperugo ha scritto:
buahahhaah, questo tuo esempio mi ricorda un sacco di cose!!!


Tipo?
10/12/2007 ore 10.16 | 1 risposta
imperugo scrive:
Re: Perché non usate lo statement using?

Tipo?
Segretissimo (chiedi a d, cmq sappi effettuare il dispose dei reader è un optional!!!
buahahah
10/12/2007 ore 11.40 | 1 risposta
m.casati scrive:
Re: Perché non usate lo statement using?

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...
10/12/2007 ore 11.57

Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.

© 1998-2008 - Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera

TagCloud
BLOG INFO
  • Post: 178
  • Commenti: 80
  • TrackBacks: 39
  • Feed blog e contenuti tecnici: RSS
  • Feed blog: RSS Atom OPML

MVP
CATEGORIE
I PIÙ LETTI DEL MESE
IN EVIDENZA