Implementar um método DisposeImplement a Dispose method

A implementação do Dispose método destina-se principalmente à liberação de recursos não gerenciados.Implementing the Dispose method is primarily for releasing unmanaged resources. Ao trabalhar com membros de instância que são IDisposable implementações, é comum fazer chamadas em cascata Dispose .When working with instance members that are IDisposable implementations, it's common to cascade Dispose calls. Há motivos adicionais para implementar Dispose , por exemplo, para liberar memória que foi alocada, remover um item que foi adicionado a uma coleção ou sinalizar a liberação de um bloqueio que foi adquirido.There are additional reasons for implementing Dispose, for example, to free memory that was allocated, remove an item that was added to a collection, or signal the release of a lock that was acquired.

O coletor de lixo do .net não aloca ou libera memória não gerenciada.The .NET garbage collector does not allocate or release unmanaged memory. O padrão para descartar um objeto, chamado de padrão Dispose, impõe a ordem no tempo de vida de um objeto.The pattern for disposing an object, referred to as the dispose pattern, imposes order on the lifetime of an object. O padrão Dispose é usado para objetos que implementam a IDisposable interface e é comum ao interagir com identificadores de arquivo e pipe, identificadores de registro, identificadores de espera ou ponteiros para blocos de memória não gerenciada.The dispose pattern is used for objects that implement the IDisposable interface, and is common when interacting with file and pipe handles, registry handles, wait handles, or pointers to blocks of unmanaged memory. Isso ocorre porque o coletor de lixo não pode recuperar objetos não gerenciados.This is because the garbage collector is unable to reclaim unmanaged objects.

Para ajudar a garantir que os recursos sempre sejam limpos adequadamente, um Dispose método deve ser idempotente, de modo que ele possa ser chamado várias vezes sem gerar uma exceção.To help ensure that resources are always cleaned up appropriately, a Dispose method should be idempotent, such that it is callable multiple times without throwing an exception. Além disso, as invocações subsequentes do Dispose não devem fazer nada.Furthermore, subsequent invocations of Dispose should do nothing.

O exemplo de código fornecido para o GC.KeepAlive método mostra como a coleta de lixo pode fazer com que um finalizador seja executado, enquanto uma referência não gerenciada para o objeto ou seus membros ainda está em uso.The code example provided for the GC.KeepAlive method shows how garbage collection can cause a finalizer to run, while an unmanaged reference to the object or its members is still in use. Pode fazer sentido utilizar GC.KeepAlive para tornar o objeto inelegível para coleta de lixo do início da rotina atual até o ponto em que esse método é chamado.It may make sense to utilize GC.KeepAlive to make the object ineligible for garbage collection from the start of the current routine to the point where this method is called.

Identificadores segurosSafe handles

Escrever código para o finalizador de um objeto é uma tarefa complexa que poderá causar problemas se não for feito corretamente.Writing code for an object's finalizer is a complex task that can cause problems if not done correctly. Assim, recomendamos que você construa objetos System.Runtime.InteropServices.SafeHandle, em vez de implementar um finalizador.Therefore, we recommend that you construct System.Runtime.InteropServices.SafeHandle objects instead of implementing a finalizer.

Um System.Runtime.InteropServices.SafeHandle é um tipo gerenciado abstrato que encapsula um System.IntPtr que identifica um recurso não gerenciado.A System.Runtime.InteropServices.SafeHandle is an abstract managed type that wraps an System.IntPtr that identifies an unmanaged resource. No Windows, ele pode identificar um identificador no UNIX, um descritor de arquivo.On Windows it might identify a handle while on Unix, a file descriptor. Ele fornece toda a lógica necessária para garantir que esse recurso seja liberado apenas uma vez, quando o SafeHandle é Descartado ou quando todas as referências a foram SafeHandle removidas e a SafeHandle instância é finalizada.It provides all of the logic necessary to ensure that this resource is released once and only once, when the SafeHandle is disposed of or when all references to the SafeHandle have been dropped and the SafeHandle instance is finalized.

O System.Runtime.InteropServices.SafeHandle é uma classe base abstrata.The System.Runtime.InteropServices.SafeHandle is an abstract base class. As classes derivadas fornecem instâncias específicas para diferentes tipos de identificador.Derived classes provide specific instances for different kinds of handle. Essas classes derivadas validam quais valores do System.IntPtr são considerados inválidos e como realmente liberar o identificador.These derived classes validate what values for the System.IntPtr are considered invalid and how to actually free the handle. Por exemplo, SafeFileHandle deriva de SafeHandle para encapsular IntPtrs que identifica identificadores/descritores de arquivos abertos e substitui seu SafeHandle.ReleaseHandle() método para fechá-lo (por meio da close função no UNIX ou na CloseHandle função no Windows).For example, SafeFileHandle derives from SafeHandle to wrap IntPtrs that identify open file handles/descriptors, and overrides its SafeHandle.ReleaseHandle() method to close it (via the close function on Unix or CloseHandle function on Windows). A maioria das APIs em bibliotecas do .NET que criam um recurso não gerenciado o encapsulará em um SafeHandle e retornará isso SafeHandle para você conforme necessário, em vez de redistribuir o ponteiro bruto.Most APIs in .NET libraries that create an unmanaged resource will wrap it in a SafeHandle and return that SafeHandle to you as needed, rather than handing back the raw pointer. Em situações em que você interage com um componente não gerenciado e Obtém um IntPtr para um recurso não gerenciado, você pode criar seu próprio SafeHandle tipo para encapsulá-lo.In situations where you interact with an unmanaged component and get an IntPtr for an unmanaged resource, you can create your own SafeHandle type to wrap it. Como resultado, poucos não SafeHandle tipos precisam implementar finalizadores; a maioria das implementações de padrão descartáveis acaba com o encapsulamento de outros recursos gerenciados, alguns dos quais podem ser SafeHandle s.As a result, few non-SafeHandle types need to implement finalizers; most disposable pattern implementations only end up wrapping other managed resources, some of which may be SafeHandles.

As seguintes classes derivadas no namespace Microsoft.Win32.SafeHandles fornecem os identificadores seguros:The following derived classes in the Microsoft.Win32.SafeHandles namespace provide safe handles:

Dispose () e Dispose (bool)Dispose() and Dispose(bool)

A interface IDisposable requer a implementação de um único método sem parâmetros, Dispose.The IDisposable interface requires the implementation of a single parameterless method, Dispose. Além disso, qualquer classe não selada deve ter um Dispose(bool) método de sobrecarga adicional a ser implementado:Also, any non-sealed class should have an additional Dispose(bool) overload method to be implemented:

  • Uma public implementação não virtual ( NonInheritable em Visual Basic) IDisposable.Dispose que não tem parâmetros.A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.

  • Um protected virtual Overridable método (no Visual Basic) Dispose cuja assinatura é:A protected virtual (Overridable in Visual Basic) Dispose method whose signature is:

    protected virtual void Dispose(bool disposing)
    {
    }
    
    Protected Overridable Sub Dispose(disposing As Boolean)
    End Sub
    

    Importante

    O disposing parâmetro deve ser false quando chamado de um finalizador e true quando chamado a partir do IDisposable.Dispose método.The disposing parameter should be false when called from a finalizer, and true when called from the IDisposable.Dispose method. Em outras palavras, é true quando chamado de forma determinística e false quando chamado de forma não determinística.In other words, it is true when deterministically called and false when non-deterministically called.

O método Dispose ()The Dispose() method

Como o public , que não é virtual ( NonInheritable em Visual Basic), o Dispose método sem parâmetros é chamado por um consumidor do tipo, sua finalidade é liberar recursos não gerenciados, executar a limpeza geral e indicar que o finalizador, se houver, não precisa ser executado.Because the public, non-virtual (NonInheritable in Visual Basic), parameterless Dispose method is called by a consumer of the type, its purpose is to free unmanaged resources, perform general cleanup, and to indicate that the finalizer, if one is present, doesn't have to run. Liberar a memória real associada a um objeto gerenciado é sempre o domínio do coletor de lixo.Freeing the actual memory associated with a managed object is always the domain of the garbage collector. Por isso, ele tem uma implementação padrão:Because of this, it has a standard implementation:

public void Dispose()
{
   // Dispose of unmanaged resources.
   Dispose(true);
   // Suppress finalization.
   GC.SuppressFinalize(this);
}
Public Sub Dispose() _
           Implements IDisposable.Dispose
    ' Dispose of unmanaged resources.
    Dispose(True)
    ' Suppress finalization.
    GC.SuppressFinalize(Me)
End Sub

O método Dispose executa toda a limpeza do objeto, de modo que o coletor de lixo não precisa mais chamar a substituição dos objetos Object.Finalize.The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalize override. Assim, a chamada para o método SuppressFinalize impede que o coletor de lixo execute o finalizador.Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. Se o tipo não possuir um finalizador, a chamada para GC.SuppressFinalize não terá efeito.If the type has no finalizer, the call to GC.SuppressFinalize has no effect. Observe que a limpeza real é executada pela Dispose(bool) sobrecarga do método.Note that the actual cleanup is performed by the Dispose(bool) method overload.

A sobrecarga do método Dispose (bool)The Dispose(bool) method overload

Na sobrecarga, o disposing parâmetro é um Boolean que indica se a chamada do método vem de um Dispose método (seu valor é true ) ou de um finalizador (seu valor é false ).In the overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

O corpo do método consiste em dois blocos de código:The body of the method consists of two blocks of code:

  • Um bloco que libera recursos não gerenciados.A block that frees unmanaged resources. Este bloco é executado independentemente do valor do parâmetro disposing.This block executes regardless of the value of the disposing parameter.

  • Um bloco condicional que libera recursos gerenciados.A conditional block that frees managed resources. Este bloco será executado se o valor de disposing for true.This block executes if the value of disposing is true. Os recursos gerenciados que ele libera podem incluir:The managed resources that it frees can include:

    • Objetos gerenciados que implementam IDisposable.Managed objects that implement IDisposable. O bloco condicional pode ser usado para chamar sua Dispose implementação (descarte em cascata).The conditional block can be used to call their Dispose implementation (cascade dispose). Se você tiver usado uma classe derivada do System.Runtime.InteropServices.SafeHandle para encapsular seu recurso não gerenciado, deverá chamar a SafeHandle.Dispose() implementação aqui.If you have used a derived class of System.Runtime.InteropServices.SafeHandle to wrap your unmanaged resource, you should call the SafeHandle.Dispose() implementation here.

    • Objetos gerenciados que consomem muita memória ou consomem recursos escassos.Managed objects that consume large amounts of memory or consume scarce resources. Atribua grandes referências de objeto gerenciado ao null para torná-las mais prováveis de serem inacessíveis.Assign large managed object references to null to make them more likely to be unreachable. Isso libera mais rápido do que se eles fossem recuperados de forma não determinística.This releases them faster than if they were reclaimed non-deterministically.

Se a chamada do método vier de um finalizador, somente o código que libera recursos não gerenciados deve ser executado.If the method call comes from a finalizer, only the code that frees unmanaged resources should execute. O implementador é responsável por garantir que o caminho falso não interaja com objetos gerenciados que podem ter sido recuperados.The implementer is responsible for ensuring the the false path doesn't interact with managed objects that may have been reclaimed. Isso é importante porque a ordem na qual o coletor de lixo destrói os objetos gerenciados durante a finalização é não determinística.This is important because the order in which the garbage collector destroys managed objects during finalization is non-deterministic.

Propagar chamadas de DisposeCascade dispose calls

Se sua classe possui um campo ou propriedade, e seu tipo implementa IDisposable , a própria classe recipiente também deve implementar IDisposable .If your class owns a field or property, and its type implements IDisposable, the containing class itself should also implement IDisposable. Uma classe que instancia uma IDisposable implementação e o armazena como um membro de instância também é responsável por sua limpeza.A class that instantiates an IDisposable implementation and storing it as an instance member, is also responsible for its cleanup. Isso é para ajudar a garantir que os tipos descartáveis referenciados recebam a oportunidade de realizar a limpeza de forma determinística através do Dispose método.This is to help ensure that the referenced disposable types are given the opportunity to deterministically perform clean up through the Dispose method. Neste exemplo, a classe é sealed (ou NotInheritable em Visual Basic).In this example, the class is sealed (or NotInheritable in Visual Basic).

public sealed class Foo : IDisposable
{
    private readonly IDisposable _bar;

    public Foo()
    {
        _bar = new Bar();
    }

    public void Dispose()
    {
        _bar?.Dispose();
    }
}
Public NotInheritable Class Foo
    Implements IDisposable

    Private ReadOnly _bar As IDisposable

    Public Sub New()
        _bar = New Bar()
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        _bar.Dispose()
    End Sub
End Class

Implementar o padrão DisposeImplement the dispose pattern

Todas as classes não seladas ou (Visual Basic classes não modificadas como NotInheritable ) devem ser consideradas uma classe base em potencial, porque elas podem ser herdadas.All non-sealed classes or (Visual Basic classes not modified as NotInheritable) should be considered a potential base class, because they could be inherited. Se você implementar o padrão Dispose para qualquer classe base em potencial, deverá fornecer o seguinte:If you implement the dispose pattern for any potential base class, you must provide the following:

  • Uma implementação de Dispose que chame o método Dispose(bool).A Dispose implementation that calls the Dispose(bool) method.
  • Um Dispose(bool) método que executa a limpeza real.A Dispose(bool) method that performs the actual cleanup.
  • Uma classe derivada de SafeHandle que envolva o recurso não gerenciado (recomendado) ou uma substituição para o método Object.Finalize.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. A SafeHandle classe fornece um finalizador, portanto, você não precisa escrever um por conta própria.The SafeHandle class provides a finalizer, so you do not have to write one yourself.

Importante

É possível que uma classe base referencie apenas objetos gerenciados e implemente o padrão Dispose.It is possible for a base class to only reference managed objects, and implement the dispose pattern. Nesses casos, um finalizador é desnecessário.In these cases, a finalizer is unnecessary. Um finalizador só será necessário se você fizer referência direta A recursos não gerenciados.A finalizer is only required if you directly reference unmanaged resources.

Aqui está o padrão geral para implementar o padrão de descarte para uma classe base que usa um identificador seguro.Here's the general pattern for implementing the dispose pattern for a base class that uses a safe handle.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class BaseClass : IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    // Instantiate a SafeHandle instance.
    private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose() => Dispose(true);

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
           // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        _disposed = true;
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class BaseClass : Implements IDisposable
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False
    ' Instantiate a SafeHandle instance.
    Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

    ' Public implementation of Dispose pattern callable by consumers.
    Public Sub Dispose() _
               Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    ' Protected implementation of Dispose pattern.
    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            handle.Dispose()
            ' Free any other managed objects here.
            '
        End If

        disposed = True
    End Sub
End Class

Observação

O exemplo anterior usa um objeto SafeFileHandle para ilustrar o padrão; qualquer objeto derivado de SafeHandle poderia ser usado em vez disso.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Observe que o exemplo não cria corretamente uma instância de seu objeto SafeFileHandle.Note that the example does not properly instantiate its SafeFileHandle object.

Aqui está o padrão geral para implementar o padrão de descarte para uma classe base que substitui Object.Finalize.Here's the general pattern for implementing the dispose pattern for a base class that overrides Object.Finalize.

using System;

class BaseClass : IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    ~BaseClass() => Dispose(false);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;
    }
}
Class BaseClass : Implements IDisposable
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False

    ' Public implementation of Dispose pattern callable by consumers.
    Public Sub Dispose() _
               Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    ' Protected implementation of Dispose pattern.
    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            ' Free any other managed objects here.
            '
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(False)
    End Sub
End Class

Dica

Em C#, você cria um finalizador substituindo Object.Finalize .In C#, you create a finalizer by overriding Object.Finalize. No Visual Basic, isso é feito com Protected Overrides Sub Finalize() .In Visual Basic, this is done with Protected Overrides Sub Finalize().

Implementar o padrão Dispose para uma classe derivadaImplement the dispose pattern for a derived class

Uma classe derivada de uma classe que implementa a interface IDisposable não deve implementar IDisposable porque a implementação da classe base IDisposable.Dispose é herdada pelas classes derivadas.A class derived from a class that implements the IDisposable interface shouldn't implement IDisposable, because the base class implementation of IDisposable.Dispose is inherited by its derived classes. Em vez disso, para limpar uma classe derivada, você fornece o seguinte:Instead, to cleanup a derived class, you provide the following:

  • Um protected override void Dispose(bool) método que substitui o método da classe base e executa a limpeza real da classe derivada.A protected override void Dispose(bool) method that overrides the base class method and performs the actual cleanup of the derived class. Esse método também deve chamar o base.Dispose(bool) MyBase.Dispose(bool) método (no Visual Basic) da classe base e passar seu status de descarte para o argumento.This method must also call the base.Dispose(bool) (MyBase.Dispose(bool) in Visual Basic) method of the base class and pass its disposing status for the argument.
  • Uma classe derivada de SafeHandle que envolva o recurso não gerenciado (recomendado) ou uma substituição para o método Object.Finalize.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. A classe SafeHandle fornece um finalizador que o libera de ter que codificar um.The SafeHandle class provides a finalizer that frees you from having to code one. Se você fornecer um finalizador, ele deverá chamar a Dispose(bool) sobrecarga com um disposing argumento de false .If you do provide a finalizer, it must call the Dispose(bool) overload with a disposing argument of false.

Aqui está o padrão geral para implementar o padrão de descarte para uma classe derivada que usa um identificador seguro:Here's the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
    // To detect redundant calls
    private bool _disposed = false;

    // Instantiate a SafeHandle instance.
    private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
           // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        _disposed = true;

        // Call base class implementation.
        base.Dispose(disposing);
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class DerivedClass : Inherits BaseClass
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False
    ' Instantiate a SafeHandle instance.
    Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

    ' Protected implementation of Dispose pattern.
    Protected Overrides Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            handle.Dispose()
            ' Free any other managed objects here.
            '
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True

        ' Call base class implementation.
        MyBase.Dispose(disposing)
    End Sub
End Class

Observação

O exemplo anterior usa um objeto SafeFileHandle para ilustrar o padrão; qualquer objeto derivado de SafeHandle poderia ser usado em vez disso.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Observe que o exemplo não cria corretamente uma instância de seu objeto SafeFileHandle.Note that the example does not properly instantiate its SafeFileHandle object.

Aqui está o padrão geral para implementar o padrão de descarte para uma classe derivada que substitui Object.Finalize:Here's the general pattern for implementing the dispose pattern for a derived class that overrides Object.Finalize:

using System;

class DerivedClass : BaseClass
{
    // To detect redundant calls
    bool _disposed = false;

    ~DerivedClass() => Dispose(false);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.
        _disposed = true;

        // Call the base class implementation.
        base.Dispose(disposing);
    }
}
Class DerivedClass : Inherits BaseClass
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False

    ' Protected implementation of Dispose pattern.
    Protected Overrides Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            ' Free any other managed objects here.
            '
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True

        ' Call the base class implementation.
        MyBase.Dispose(disposing)
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(False)
    End Sub
End Class

Implementar o padrão Dispose com identificadores segurosImplement the dispose pattern with safe handles

O exemplo a seguir ilustra o padrão de descarte para uma classe base, DisposableStreamResource, a qual usa um identificador seguro para encapsular recursos não gerenciados.The following example illustrates the dispose pattern for a base class, DisposableStreamResource, that uses a safe handle to encapsulate unmanaged resources. Define uma classe DisposableStreamResource que usa SafeFileHandle para encapsular um objeto Stream que representa um arquivo aberto.It defines a DisposableStreamResource class that uses a SafeFileHandle to wrap a Stream object that represents an open file. A classe também inclui uma única propriedade, Size , que retorna o número total de bytes no fluxo de arquivos.The class also includes a single property, Size, that returns the total number of bytes in the file stream.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

public class DisposableStreamResource : IDisposable
{
    // Define constants.
    protected const uint GENERIC_READ = 0x80000000;
    protected const uint FILE_SHARE_READ = 0x00000001;
    protected const uint OPEN_EXISTING = 3;
    protected const uint FILE_ATTRIBUTE_NORMAL = 0x80;
    private const int INVALID_FILE_SIZE = unchecked((int)0xFFFFFFFF);

    // Define Windows APIs.
    [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode)]
    protected static extern SafeFileHandle CreateFile(
        string lpFileName, uint dwDesiredAccess,
        uint dwShareMode, IntPtr lpSecurityAttributes,
        uint dwCreationDisposition, uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll")]
    private static extern int GetFileSize(
        SafeFileHandle hFile, out int lpFileSizeHigh);

    // Define locals.
    private bool _disposed = false;
    private readonly SafeFileHandle _safeHandle;
    private readonly int _upperWord;

    public DisposableStreamResource(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName))
        {
            throw new ArgumentException("The fileName cannot be null or an empty string");
        }

        _safeHandle = CreateFile(
            fileName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);

        // Get file size.
        Size = GetFileSize(_safeHandle, out _upperWord);
        if (Size == INVALID_FILE_SIZE)
        {
            Size = -1;
        }
        else if (_upperWord > 0)
        {
            Size = (((long)_upperWord) << 32) + Size;
        }
    }

    public long Size { get; }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        // Dispose of managed resources here.
        if (disposing)
        {
            _safeHandle?.Dispose();
        }

        // Dispose of any unmanaged resources not wrapped in safe handles.

        _disposed = true;
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource : Implements IDisposable
    ' Define constants.
    Protected Const GENERIC_READ As UInteger = &H80000000UI
    Protected Const FILE_SHARE_READ As UInteger = &H0I
    Protected Const OPEN_EXISTING As UInteger = 3
    Protected Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
    Private Const INVALID_FILE_SIZE As Integer = &HFFFFFFFF

    ' Define Windows APIs.
    Protected Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (
        lpFileName As String, dwDesiredAccess As UInt32,
        dwShareMode As UInt32, lpSecurityAttributes As IntPtr,
        dwCreationDisposition As UInt32, dwFlagsAndAttributes As UInt32,
        hTemplateFile As IntPtr) As SafeFileHandle

    Private Declare Function GetFileSize Lib "kernel32" (
        hFile As SafeFileHandle, ByRef lpFileSizeHigh As Integer) As Integer

    ' Define locals.
    Private disposed As Boolean = False
    Private ReadOnly safeHandle As SafeFileHandle
    Private ReadOnly upperWord As Integer

    Public Sub New(fileName As String)
        If String.IsNullOrWhiteSpace(fileName) Then
            Throw New ArgumentNullException("The fileName cannot be null or an empty string")
        End If

        safeHandle = CreateFile(
            fileName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)

        ' Get file size.
        Size = GetFileSize(safeHandle, upperWord)
        If Size = INVALID_FILE_SIZE Then
            Size = -1
        ElseIf upperWord > 0 Then
            Size = (CLng(upperWord) << 32) + Size
        End If
    End Sub

    Public ReadOnly Property Size As Long

    Public Sub Dispose() _
              Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposed Then Exit Sub

        ' Dispose of managed resources here.
        If disposing Then
            safeHandle.Dispose()
        End If

        ' Dispose of any unmanaged resources not wrapped in safe handles.

        disposed = True
    End Sub
End Class

Implementar o padrão Dispose para uma classe derivada com identificadores segurosImplement the dispose pattern for a derived class with safe handles

O exemplo a seguir ilustra o padrão de descarte para uma classe derivada, DisposableStreamResource2, que herda da classe DisposableStreamResource apresentada no exemplo anterior.The following example illustrates the dispose pattern for a derived class, DisposableStreamResource2, that inherits from the DisposableStreamResource class presented in the previous example. A classe acrescenta um método adicional, WriteFileInfo, e usa um objeto SafeFileHandle para encapsular o identificador do arquivo gravável.The class adds an additional method, WriteFileInfo, and uses a SafeFileHandle object to wrap the handle of the writable file.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

public class DisposableStreamResource2 : DisposableStreamResource
{
    // Define additional constants.
    protected const uint GENERIC_WRITE = 0x40000000;
    protected const uint OPEN_ALWAYS = 4;

    // Define additional APIs.
    [DllImport("kernel32.dll")]
    protected static extern bool WriteFile(
        SafeFileHandle safeHandle, string lpBuffer,
        int nNumberOfBytesToWrite, out int lpNumberOfBytesWritten,
        IntPtr lpOverlapped);

    // To detect redundant calls
    private bool _disposed = false;
    private bool _created = false;
    private SafeFileHandle _safeHandle;
    private readonly string _fileName;

    public DisposableStreamResource2(string fileName) : base(fileName) => _fileName = fileName;

    public void WriteFileInfo()
    {
        if (!_created)
        {
            _safeHandle = CreateFile(
                @".\FileInfo.txt", GENERIC_WRITE, 0, IntPtr.Zero,
                OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);

            _created = true;
        }

        string output = $"{_fileName}: {Size:N0} bytes\n";
        _ = WriteFile(_safeHandle, output, output.Length, out _, IntPtr.Zero);
    }

    protected override void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        // Release any managed resources here.
        if (disposing)
        {
            // Dispose managed state (managed objects).
            _safeHandle?.Dispose();
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;

        // Call the base class implementation.
        base.Dispose(disposing);
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource2 : Inherits DisposableStreamResource
    ' Define additional constants.
    Protected Const GENERIC_WRITE As Integer = &H40000000
    Protected Const OPEN_ALWAYS As Integer = 4

    ' Define additional APIs.
    Protected Declare Function WriteFile Lib "kernel32.dll" (
        safeHandle As SafeFileHandle, lpBuffer As String,
        nNumberOfBytesToWrite As Integer, ByRef lpNumberOfBytesWritten As Integer,
        lpOverlapped As Object) As Boolean

    ' Define locals.
    Private disposed As Boolean = False
    Private created As Boolean = False
    Private safeHandle As SafeFileHandle
    Private ReadOnly filename As String

    Public Sub New(filename As String)
        MyBase.New(filename)
        Me.filename = filename
    End Sub

    Public Sub WriteFileInfo()
        If Not created Then
            safeHandle = CreateFile(
                ".\FileInfo.txt", GENERIC_WRITE, 0, IntPtr.Zero,
                OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)
            created = True
        End If

        Dim output As String = $"{filename }: {Size:N0} bytes {vbCrLf }"
        Dim result = WriteFile(safeHandle, output, output.Length, 0&, Nothing)
    End Sub

    Protected Overridable Overloads Sub Dispose(disposing As Boolean)
        If disposed Then Exit Sub

        ' Release any managed resources here.
        If disposing Then
            safeHandle?.Dispose()
        End If

        disposed = True
        ' Release any unmanaged resources not wrapped by safe handles here.

        ' Call the base class implementation.
        MyBase.Dispose(disposing)
    End Sub
End Class

Veja tambémSee also