Usando objetos que implementam IDisposableUsing objects that implement IDisposable

O coletor de lixo do Common Language Runtime recupera a memória usada por objetos gerenciados, mas os tipos que usam recursos não gerenciados implementam a IDisposable interface para permitir que os recursos necessários a esses recursos não gerenciados sejam recuperados.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. Após terminar de usar um objeto que implementa IDisposable, você deverá chamar a implementação de IDisposable.Dispose do objeto.When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. É possível fazer isso de duas formas:You can do this in one of two ways:

  • Com a using instrução C# ( Using em Visual Basic).With the C# using statement (Using in Visual Basic).
  • Implementando um try/finally bloco e chamando o IDisposable.Dispose no finally .By implementing a try/finally block, and calling the IDisposable.Dispose in the finally.

A instrução usingThe using statement

A using instrução em C# e a Using instrução em Visual Basic simplificam o código que você deve escrever para limpar um objeto.The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to cleanup an object. A instrução using obtém um ou mais recursos, executa as instruções que você especifica e descarta o objeto automaticamente.The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. Entretanto, a instrução using é útil apenas para os objetos que são usados no escopo do método no qual eles são criados.However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

O exemplo a seguir usa a instrução using para criar e liberar um objeto 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

Embora a StreamReader classe implemente a IDisposable interface, que indica que ela usa um recurso não gerenciado, o exemplo não chama explicitamente o StreamReader.Dispose método.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 o compilador do C# ou do Visual Basic encontra a instrução using, ele emite a IL (linguagem intermediária) que equivale ao seguinte código que contém explicitamente um bloco 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

A instrução using do C# também permite que você adquira vários recursos em uma única instrução, o que é internamente equivalente a instruções using aninhadas.The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. O exemplo a seguir cria instancia dois objetos StreamReader para ler o conteúdo de dois arquivos diferentes.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.
            //
        }
    }
}

Bloco Try/finallyTry/finally block

Em vez de incluir um bloco try/finally em uma instrução using, você pode optar por implementar diretamente o bloco try/finally.Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. Pode ser seu estilo de codificação pessoal ou você pode desejar fazer isso por um dos seguintes motivos:It may be your personal coding style, or you might want to do this for one of the following reasons:

  • Para incluir um catch bloco para tratar as exceções lançadas no try bloco.To include a catch block to handle exceptions thrown in the try block. Caso contrário, as exceções geradas na using instrução não serão manipuladas.Otherwise, any exceptions thrown within the using statement are unhandled.

  • Para criar uma instância de um objeto que implementa IDisposable cujo escopo não é local para o bloco dentro do qual é declarado.To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

O exemplo a seguir é semelhante ao exemplo anterior, exceto que ele usa um bloco try/catch/finally para criar uma instância, usar e descartar um objeto StreamReader e também para manipular todas as exceções lançadas pelo construtor StreamReader e pelo método 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. O código no finally bloco verifica se o objeto que implementa IDisposable não está null antes de chamar o Dispose método.The code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. Não fazer isso poderá levar a uma exceção de NullReferenceException em tempo de execução.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

Você poderá seguir esse padrão básico se optar por implementar ou precisar implementar um bloco try/finally, pois a linguagem de programação não oferece suporte a uma instrução using, mas permite chamadas diretas para o método 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.

Membros da instância IDisposableIDisposable instance members

Se uma classe mantém uma IDisposable implementação como um membro de instância, seja um campo ou uma propriedade, a classe também deve implementar IDisposable .If a class holds an IDisposable implementation as an instance member, either a field or a property, the class should also implement IDisposable. Para obter mais informações, consulte implementar uma disposição em cascata.For more information, see implement a cascade dispose.

Confira tambémSee also