Uso di oggetti che implementano IDisposableUsing objects that implement IDisposable

Il recupero della memoria usata dagli oggetti gestiti viene eseguito dal Garbage Collector di Common Language Runtime, ma i tipi che usano le risorse non gestite implementano l'interfaccia IDisposable per consentire il recupero di tale memoria non gestita.The common language runtime's garbage collector reclaims the memory used by managed objects, but types that use unmanaged resources implement the IDisposable interface to allow the memory allocated to these unmanaged resources to be reclaimed. Dopo avere utilizzato un oggetto che implementa IDisposable, è necessario chiamare l'implementazione IDisposable.Dispose dell'oggetto.When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. Questa operazione può essere eseguita in due modi:You can do this in one of two ways:

  • Con l'istruzione using in C# o l'istruzione Using in Visual Basic.With the C# using statement or the Visual Basic Using statement.

  • Implementando un blocco try/finally.By implementing a try/finally block.

Istruzione usingThe using statement

L'istruzione using in C# e l'istruzione Using in Visual Basic semplificano il codice da scrivere per creare e pulire un oggetto.The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to create and clean up an object. L'istruzione using ottiene una o più risorse, esegue le istruzioni specificate ed elimina l'oggetto in modo automatico.The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. L'istruzione using è comunque utile solo per gli oggetti usati nell'ambito del metodo in cui vengono costruiti.However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

Nell'esempio seguente viene utilizzata l'istruzione using per creare e rilasciare un oggetto System.IO.StreamReader.The following example uses the using statement to create and release a System.IO.StreamReader object.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer = new Char[50];
      using (StreamReader s = new StreamReader("File1.txt")) {
         int charsRead = 0;
         while (s.Peek() != -1) {
            charsRead = s.Read(buffer, 0, buffer.Length);
            //
            // Process characters read.
            //   
         }
         s.Close();    
      }

   }
}
Imports System.IO

Module Example
   Public Sub Main()
      Dim buffer(49) As Char
      Using s As New StreamReader("File1.txt")
         Dim charsRead As Integer
         Do While s.Peek() <> -1
            charsRead = s.Read(buffer, 0, buffer.Length)         
            ' 
            ' Process characters read.
            '
         Loop
         s.Close()
      End Using
   End Sub
End Module

Si noti che, anche se la classe StreamReader implementa l'interfaccia IDisposable, a indicare che utilizza una risorsa non gestita, nell'esempio non viene chiamato il metodo StreamReader.Dispose in modo esplicito.Note that although the StreamReader class implements the IDisposable interface, which indicates that it uses an unmanaged resource, the example doesn't explicitly call the StreamReader.Dispose method. Quando nel compilatore C# o Visual Basic viene rilevata l'istruzione using, viene generato il linguaggio intermedio (IL) equivalente al codice seguente, che contiene un blocco try/finally in modo esplicito.When the C# or Visual Basic compiler encounters the using statement, it emits intermediate language (IL) that is equivalent to the following code that explicitly contains a try/finally block.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer = new Char[50];
      {
         StreamReader s = new StreamReader("File1.txt"); 
         try {
            int charsRead = 0;
            while (s.Peek() != -1) {
               charsRead = s.Read(buffer, 0, buffer.Length);
               //
               // Process characters read.
               //   
            }
            s.Close();
         }
         finally {
            if (s != null)
               ((IDisposable)s).Dispose();     
         }       
      }
   }
}
Imports System.IO

Module Example
   Public Sub Main()
      Dim buffer(49) As Char
''      Dim s As New StreamReader("File1.txt")
With s As New StreamReader("File1.txt")
      Try
         Dim charsRead As Integer
         Do While s.Peek() <> -1
            charsRead = s.Read(buffer, 0, buffer.Length)         
            ' 
            ' Process characters read.
            '
         Loop
         s.Close()
      Finally
         If s IsNot Nothing Then DirectCast(s, IDisposable).Dispose()
      End Try
End With
   End Sub
End Module

L'istruzione using C# è consente anche di acquisire più risorse in un'unica istruzione, che equivale internamente all'uso di più istruzioni using annidate.The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. Nell'esempio seguente viene creata l'istanza di due oggetti StreamReader per leggere il contenuto di due diversi file.The following example instantiates two StreamReader objects to read the contents of two different files.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer1 = new Char[50], buffer2 = new Char[50];
      
      using (StreamReader version1 = new StreamReader("file1.txt"),
                          version2 = new StreamReader("file2.txt")) {
         int charsRead1, charsRead2 = 0;
         while (version1.Peek() != -1 && version2.Peek() != -1) {
            charsRead1 = version1.Read(buffer1, 0, buffer1.Length);
            charsRead2 = version2.Read(buffer2, 0, buffer2.Length);
            //
            // Process characters read.
            //
         }
         version1.Close();
         version2.Close();
      }
   }
}

Blocco try/finallyTry/finally block

Anziché eseguire il wrapping di un blocco try/finally in un'istruzione using, è possibile implementare direttamente il blocco try/finally.Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. La scelta può essere espressione dello stile di codifica personale oppure essere dovuta a uno dei seguenti motivi:This may be your personal coding style, or you might want to do this for one of the following reasons:

  • Includere un blocco catch per gestire eventuali eccezioni generate nel blocco try.To include a catch block to handle any exceptions thrown in the try block. In caso contrario, tutte le eccezioni generate dall'istruzione using non vengono gestite, analogamente alle eccezioni generate all'interno del blocco using se un blocco try/catch non è presente.Otherwise, any exceptions thrown by the using statement are unhandled, as are any exceptions thrown within the using block if a try/catch block isn't present.

  • Creare un'istanza di un oggetto che implementa IDisposable il cui ambito non è locale rispetto al blocco in cui viene dichiarato.To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

L'esempio seguente è simile a quello precedente, con la differenza che in questo viene usato un blocco try/catch/finally per creare un'istanza di un oggetto StreamReader, utilizzarla ed eliminarla e per gestire le eccezioni generate dal costruttore StreamReader e dal relativo metodo ReadToEnd.The following example is similar to the previous example, except that it uses a try/catch/finally block to instantiate, use, and dispose of a StreamReader object, and to handle any exceptions thrown by the StreamReader constructor and its ReadToEnd method. Si noti che il codice nel blocco finally controlla che l'oggetto che implementa IDisposable non sia null prima di chiamare il metodo Dispose.Note that the code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. L'omissione di tale controllo può provocare un'eccezione NullReferenceException in fase di esecuzione.Failure to do this can result in a NullReferenceException exception at run time.

using System;
using System.Globalization;
using System.IO;

public class Example
{
   public static void Main()
   {
      StreamReader sr = null;
      try {
         sr = new StreamReader("file1.txt");
         String contents = sr.ReadToEnd();
         sr.Close();
         Console.WriteLine("The file has {0} text elements.", 
                           new StringInfo(contents).LengthInTextElements);    
      }      
      catch (FileNotFoundException) {
         Console.WriteLine("The file cannot be found.");
      }   
      catch (IOException) {
         Console.WriteLine("An I/O error has occurred.");
      }
      catch (OutOfMemoryException) {
         Console.WriteLine("There is insufficient memory to read the file.");   
      }
      finally {
         if (sr != null) sr.Dispose();     
      }
   }
}
Imports System.Globalization
Imports System.IO

Module Example
   Public Sub Main()
      Dim sr As StreamReader = Nothing
      Try 
         sr = New StreamReader("file1.txt")
         Dim contents As String = sr.ReadToEnd()
         sr.Close()
         Console.WriteLine("The file has {0} text elements.", 
                           New StringInfo(contents).LengthInTextElements)    
      Catch e As FileNotFoundException
         Console.WriteLine("The file cannot be found.")
      Catch e As IOException
         Console.WriteLine("An I/O error has occurred.")
      Catch e As OutOfMemoryException
         Console.WriteLine("There is insufficient memory to read the file.")   
      Finally 
         If sr IsNot Nothing Then sr.Dispose()     
      End Try
   End Sub
End Module

È possibile usare questo modello di base se si decide di implementare o è necessario implementare un blocco try/finally, poiché il linguaggio di programmazione non supporta un'istruzione using ma consente chiamate dirette al metodo Dispose.You can follow this basic pattern if you choose to implement or must implement a try/finally block, because your programming language doesn't support a using statement but does allow direct calls to the Dispose method.

Vedere ancheSee also

Pulizia delle risorse non gestite Cleaning Up Unmanaged Resources
Istruzione using (Riferimenti per C#) using Statement (C# Reference)
Istruzione using (Visual Basic)Using Statement (Visual Basic)