Utilisation d’objets implémentant IDisposableUsing objects that implement IDisposable

Le « garbage collector » de l’common language runtime récupère la mémoire utilisée par les objets managés, mais les types qui utilisent des ressources non managées implémentent l' IDisposable interface pour permettre la récupération des ressources requises par ces ressources non managées.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 resources needed by these unmanaged resources to be reclaimed. Une fois que vous avez fini d'utiliser un objet qui implémente IDisposable, vous devez appeler l'implémentation de IDisposable.Dispose de l'objet.When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. Vous pouvez le faire de deux façons :You can do this in one of two ways:

  • Avec l' using instruction C# ( Using dans Visual Basic).With the C# using statement (Using in Visual Basic).
  • En implémentant un try/finally bloc et en appelant le IDisposable.Dispose dans le finally .By implementing a try/finally block, and calling the IDisposable.Dispose in the finally.

Instruction usingThe using statement

L' using instruction en C# et l' Using instruction dans Visual Basic simplifient le code que vous devez écrire pour nettoyer un objet.The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to cleanup an object. L’instruction using obtient une ou plusieurs ressources, exécute les instructions que vous spécifiez, puis supprime automatiquement l’objet.The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. Toutefois, l’instruction using est utile uniquement pour les objets utilisés dans la portée de la méthode dans laquelle elles sont construites.However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

L’exemple suivant utilise l’instruction using pour créer et libérer un objet System.IO.StreamReader.The following example uses the using statement to create and release a System.IO.StreamReader object.

using System;
using System.IO;

class Example
{
   static void Main()
   {
      char[] buffer = new char[50];
      using var streamReader = new StreamReader("file1.txt");
      
      int charsRead = 0;
      while (streamReader.Peek() != -1)
      {
         charsRead = streamReader.Read(buffer, 0, buffer.Length);
         //
         // Process characters read.
         //
      }
   }
}
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
      End Using
   End Sub
End Module

Bien que la StreamReader classe implémente l' IDisposable interface, ce qui indique qu’elle utilise une ressource non managée, l’exemple n’appelle pas explicitement la StreamReader.Dispose méthode.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. Quand le compilateur C# ou Visual Basic rencontre l’instruction using, il émet en langage intermédiaire qui est équivalent au code suivant contenant explicitement un bloc try/finally.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;

class Example
{
    static void Main()
    {
        char[] buffer = new char[50];
        var streamReader = new StreamReader("file1.txt");
        try
        {
            int charsRead = 0;
            while (streamReader.Peek() != -1)
            {
                charsRead = streamReader.Read(buffer, 0, buffer.Length);
                //
                // Process characters read.
                //
            }
        }
        finally
        {
            if (streamReader != null)
            {
                ((IDisposable)streamReader).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
      Finally
         If s IsNot Nothing Then DirectCast(s, IDisposable).Dispose()
      End Try
End With
   End Sub
End Module

L’instruction using en C# vous permet d’acquérir plusieurs ressources dans une seule instruction, ce qui équivaut en interne à des instructions using imbriquées.The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. L'exemple suivant instancie deux objets StreamReader pour lire le contenu de deux fichiers différents.The following example instantiates two StreamReader objects to read the contents of two different files.

using System.IO;

class Example
{
    static void Main()
    {
        char[] buffer1 = new char[50];
        char[] 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.
            //
        }
    }
}

Bloc try/finallyTry/finally block

Au lieu d’encapsuler un bloc try/finally dans une instruction using, vous pouvez choisir d’implémenter le bloc try/finally directement.Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. Il peut s’agir de votre style de codage personnel, ou vous pouvez le faire pour l’une des raisons suivantes :It may be your personal coding style, or you might want to do this for one of the following reasons:

  • Pour inclure un catch bloc pour gérer les exceptions levées dans le try bloc.To include a catch block to handle exceptions thrown in the try block. Sinon, toutes les exceptions levées dans l' using instruction ne sont pas gérées.Otherwise, any exceptions thrown within the using statement are unhandled.

  • Pour instancier un objet qui implémente IDisposable dont la portée n'est pas locale au bloc dans lequel elle est déclarée.To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

L'exemple suivant est similaire à l'exemple précédent, mais il utilise un bloc try/catch/finally pour instancier, utiliser et supprimer un objet StreamReader, ainsi que pour gérer les exceptions levées par le constructeur StreamReader et sa méthode 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. Le code du finally bloc vérifie que l’objet qui implémente IDisposable n’est pas null avant d’appeler la Dispose méthode.The code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. La non-exécution de cette opération peut générer une NullReferenceException au moment de l'exécution.Failure to do this can result in a NullReferenceException exception at run time.

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

class Example
{
    static void Main()
    {
        StreamReader? streamReader = null;
        try
        {
            streamReader = new StreamReader("file1.txt");
            string contents = streamReader.ReadToEnd();
            var info = new StringInfo(contents);
            Console.WriteLine($"The file has {info.LengthInTextElements} text elements.");
        }
        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
        {
            streamReader?.Dispose();
        }
    }
}
Imports System.Globalization
Imports System.IO

Module Example
    Sub Main()
        Dim streamReader As StreamReader = Nothing
        Try
            streamReader = New StreamReader("file1.txt")
            Dim contents As String = streamReader.ReadToEnd()
            Dim info As StringInfo = New StringInfo(contents)
            Console.WriteLine($"The file has {info.LengthInTextElements} text elements.")
        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 streamReader IsNot Nothing Then streamReader.Dispose()
        End Try
    End Sub
End Module

Vous pouvez suivre ce modèle de base si vous choisissez d’implémenter (ou que vous devez implémenter) un bloc try/finally, car votre langage de programmation ne prend pas en charge l’instruction using, mais autorise des appels directs à la méthode 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.

Membres d’instance IDisposableIDisposable instance members

Si une classe contient une IDisposable implémentation en tant que membre d’instance, qu’il s’agisse d’un champ ou d’une propriété, la classe doit également implémenter IDisposable .If a class holds an IDisposable implementation as an instance member, either a field or a property, the class should also implement IDisposable. Pour plus d’informations, consultez implémenter une suppression en cascade.For more information, see implement a cascade dispose.

Voir aussiSee also