Como implementar um método DisposeImplementing a Dispose method
Você implementa um método Dispose para liberar recursos não gerenciados usados pelo seu aplicativo.You implement a Dispose method to release unmanaged resources used by your application. O coletor de lixo .NET não alocar nem libera memória não gerenciada.The .NET garbage collector does not allocate or release unmanaged memory.
O padrão para o descarte um objeto, conhecido como padrão Dispose, impõe ordem no tempo de vida de um objeto.The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object. O padrão de descarte é usado somente para os objetos que acessam recursos não gerenciados, como 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 only for objects that access unmanaged resources, such as file and pipe handles, registry handles, wait handles, or pointers to blocks of unmanaged memory. Isso ocorre porque o coletor de lixo é muito eficiente para recuperar objetos gerenciados não usados, mas não é capaz de recuperar objetos não gerenciados.This is because the garbage collector is very efficient at reclaiming unused managed objects, but it is unable to reclaim unmanaged objects.
O padrão de descarte tem duas variações:The dispose pattern has two variations:
Você envolve cada recurso não gerenciado usado por um tipo em um identificador seguro (ou seja, em uma classe derivada de System.Runtime.InteropServices.SafeHandle).You wrap each unmanaged resource that a type uses in a safe handle (that is, in a class derived from System.Runtime.InteropServices.SafeHandle). Nesse caso, você implementa a interface IDisposable e um método
Dispose(Boolean)
adicional.In this case, you implement the IDisposable interface and an additionalDispose(Boolean)
method. Essa é a variação recomendada e não requer a substituição do método Object.Finalize.This is the recommended variation and doesn't require overriding the Object.Finalize method.Observação
O namespace Microsoft.Win32.SafeHandles fornece um conjunto de classes derivadas de SafeHandle, que são listadas na seção Usando identificadores seguros.The Microsoft.Win32.SafeHandles namespace provides a set of classes derived from SafeHandle, which are listed in the Using safe handles section. Se não conseguir encontrar uma classe adequada para liberar seu recurso não gerenciado, você poderá implementar sua própria subclasse de SafeHandle.If you can't find a class that is suitable for releasing your unmanaged resource, you can implement your own subclass of SafeHandle.
Você implementa a interface IDisposable e um método
Dispose(Boolean)
adicional, além de substituir o método Object.Finalize.You implement the IDisposable interface and an additionalDispose(Boolean)
method, and you also override the Object.Finalize method. Você deve substituir Finalize para garantir que os recursos não gerenciados sejam descartados se sua implementação de IDisposable.Dispose não for chamada por um consumidor do seu tipo.You must override Finalize to ensure that unmanaged resources are disposed of if your IDisposable.Dispose implementation is not called by a consumer of your type. Se você usar a técnica recomendada discutida no item anterior, a classe System.Runtime.InteropServices.SafeHandle fará isso em seu nome.If you use the recommended technique discussed in the previous bullet, the System.Runtime.InteropServices.SafeHandle class does this on your behalf.
Para ajudar a garantir que os recursos sejam sempre limpos corretamente, um método Dispose deve poder 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 callable multiple times without throwing an exception.
O exemplo de código fornecido para o método GC.KeepAlive mostra a agressividade com a qual uma coleta de lixo pode fazer com que um finalizador seja executado enquanto um membro do objeto recuperado ainda está em execução.The code example provided for the GC.KeepAlive method shows how aggressive garbage collection can cause a finalizer to run while a member of the reclaimed object is still executing. É uma boa ideia chamar o método KeepAlive no final de um método Dispose longo.It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method.
Dispose() e Dispose(Boolean)Dispose() and Dispose(Boolean)
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. No entanto, o padrão de descarte requer que dois métodos Dispose
sejam implementados:However, the dispose pattern requires two Dispose
methods to be implemented:
Uma implementação pública não virtual (
NonInheritable
no Visual Basic) de IDisposable.Dispose que não possua parâmetros.A public non-virtual (NonInheritable
in Visual Basic) IDisposable.Dispose implementation that has no parameters.Um método
Overridable
virtual protegido (Dispose
no Visual Basic) 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)
A sobrecarga Dispose()The Dispose() overload
Como o método público, não virtual (NonInheritable
no Visual Basic) e sem parâmetro Dispose
é chamado por um consumidor do tipo, sua finalidade é liberar recursos não gerenciados e indicar que o finalizador, se houver um, 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 and to indicate that the finalizer, if one is present, doesn't have to run. 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 o trabalho real de liberar recursos não gerenciado é executado pela segunda sobrecarga do método Dispose
.Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose
method.
A sobrecarga Dispose(Boolean)The Dispose(Boolean) overload
Na segunda sobrecarga, o parâmetro disposing é um Boolean que indica se a chamada do método é proveniente de um método Dispose (seu valor é true
) ou de um finalizador (seu valor é false
).In the second 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 thedisposing
parameter.Um bloco condicional que libera recursos gerenciados.A conditional block that frees managed resources. Este bloco será executado se o valor de
disposing
fortrue
.This block executes if the value ofdisposing
istrue
. 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 implementação de Dispose.The conditional block can be used to call their Dispose implementation. Se você usou um indicador seguro para encapsular o recurso não gerenciado, é necessário chamar a implementação de SafeHandle.Dispose(Boolean) aqui.If you have used a safe handle to wrap your unmanaged resource, you should call the SafeHandle.Dispose(Boolean) 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. Liberar esses objetos explicitamente no método
Dispose
libera-os mais rápido do que se eles fossem recuperados de forma não determinística pelo coletor de lixo.Freeing these objects explicitly in theDispose
method releases them faster than if they were reclaimed non-deterministically by the garbage collector.
Se a chamada do método vier de um finalizador (isto é, se disposing for false
), somente o código que libera os recursos não gerenciados é executado.If the method call comes from a finalizer (that is, if disposing is false
), only the code that frees unmanaged resources executes. Como a ordem em que o coletor de lixo destrói objetos gerenciados durante a finalização não é definida, chamar essa sobrecarga Dispose
com um valor de false
impede que o finalizador tente liberar os recursos gerenciados que já podem ter sido recuperados.Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Dispose
overload with a value of false
prevents the finalizer from trying to release managed resources that may have already been reclaimed.
Implementando o padrão de descarte para uma classe baseImplementing the dispose pattern for a base class
Se você implementar o padrão de descarte para uma classe base, deverá fornecer o seguinte:If you implement the dispose pattern for a base class, you must provide the following:
Importante
É preciso implementar esse padrão para todas as classes de base que implementam Dispose() e não são sealed
(NotInheritable
no Visual Basic).You should implement this pattern for all base classes that implement Dispose() and are not sealed
(NotInheritable
in Visual Basic).
Uma implementação de Dispose que chame o método
Dispose(Boolean)
.A Dispose implementation that calls theDispose(Boolean)
method.Um método
Dispose(Boolean)
que execute o trabalho real de liberar recursos.ADispose(Boolean)
method that performs the actual work of releasing resources.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.
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
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
// 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) {
handle.Dispose();
// Free any other managed objects here.
//
}
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
{
// Flag: Has Dispose already been called?
bool disposed = 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) {
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
}
~BaseClass()
{
Dispose(false);
}
}
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
Observação
No C#, você deve substituir Object.Finalize definindo um destruidor.In C#, you override Object.Finalize by defining a destructor.
Implementando o padrão de descarte para uma classe derivadaImplementing 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 liberar recursos de uma classe derivada, você fornece o seguinte:Instead, to release resources of a derived class, you provide the following:
Um método
protected Dispose(Boolean)
que substitua o método da classe base e execute o trabalho real de liberar os recursos da classe derivada.Aprotected Dispose(Boolean)
method that overrides the base class method and performs the actual work of releasing the resources of the derived class. Esse método também deve chamar o métodoDispose(Boolean)
da classe base e passar seu status de descarte para o argumento.This method should also call theDispose(Boolean)
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 sobrecarga de
Dispose(Boolean)
com um argumento disposing defalse
.If you do provide a finalizer, it should call theDispose(Boolean)
overload with a disposing argument offalse
.
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
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing) {
handle.Dispose();
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
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
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing) {
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
// Call the base class implementation.
base.Dispose(disposing);
}
~DerivedClass()
{
Dispose(false);
}
}
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
Observação
No C#, você deve substituir Object.Finalize definindo um destruidor.In C#, you override Object.Finalize by defining a destructor.
Usando identificadores segurosUsing safe 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.
As classes derivadas da classe System.Runtime.InteropServices.SafeHandle simplificam problemas de vida útil de objetos ao atribuir e liberar identificadores sem interrupção.Classes derived from the System.Runtime.InteropServices.SafeHandle class simplify object lifetime issues by assigning and releasing handles without interruption. Elas contêm um finalizador crítico que certamente será executado enquanto um domínio de aplicativo estiver descarregando.They contain a critical finalizer that is guaranteed to run while an application domain is unloading. Para obter mais informações sobre as vantagens de usar um identificador seguro, consulte System.Runtime.InteropServices.SafeHandle.For more information about the advantages of using a safe handle, see System.Runtime.InteropServices.SafeHandle. 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:
As classes SafeFileHandle, SafeMemoryMappedFileHandle e SafePipeHandle para arquivos, arquivos mapeados na memória e pipes.The SafeFileHandle, SafeMemoryMappedFileHandle, and SafePipeHandle class, for files, memory mapped files, and pipes.
A classe SafeMemoryMappedViewHandle para exibições de memória.The SafeMemoryMappedViewHandle class, for memory views.
As classes SafeNCryptKeyHandle, SafeNCryptProviderHandle e SafeNCryptSecretHandle para construtores de criptografia.The SafeNCryptKeyHandle, SafeNCryptProviderHandle, and SafeNCryptSecretHandle classes, for cryptography constructs.
A classe SafeRegistryHandle para chaves do registro.The SafeRegistryHandle class, for registry keys.
A classe SafeWaitHandle para identificadores de espera.The SafeWaitHandle class, for wait handles.
Usando um identificador seguro para implementar o padrão de descarte para uma classe baseUsing a safe handle to implement the dispose pattern for a base class
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 DisposableResource
que usa SafeFileHandle para encapsular um objeto Stream que representa um arquivo aberto.It defines a DisposableResource
class that uses a SafeFileHandle to wrap a Stream object that represents an open file. O método DisposableResource
também inclui uma única propriedade, Size
, a qual retorna o número total de bytes no fluxo de arquivos.The DisposableResource
method 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.IO;
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;
protected IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private const int INVALID_FILE_SIZE = unchecked((int) 0xFFFFFFFF);
// Define Windows APIs.
[DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode)]
protected static extern IntPtr 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 SafeFileHandle safeHandle;
private long bufferSize;
private int upperWord;
public DisposableStreamResource(string filename)
{
if (filename == null)
throw new ArgumentNullException("The filename cannot be null.");
else if (filename == "")
throw new ArgumentException("The filename cannot be an empty string.");
IntPtr handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (handle != INVALID_HANDLE_VALUE)
safeHandle = new SafeFileHandle(handle, true);
else
throw new FileNotFoundException(String.Format("Cannot open '{0}'", filename));
// Get file size.
bufferSize = GetFileSize(safeHandle, out upperWord);
if (bufferSize == INVALID_FILE_SIZE)
bufferSize = -1;
else if (upperWord > 0)
bufferSize = (((long)upperWord) << 32) + bufferSize;
}
public long Size
{ get { return bufferSize; } }
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 = &H0000000i
Protected Const OPEN_EXISTING As UInteger = 3
Protected Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
Protected INVALID_HANDLE_VALUE As New IntPtr(-1)
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 IntPtr
Private Declare Function GetFileSize Lib "kernel32" (hFile As SafeFileHandle,
ByRef lpFileSizeHigh As Integer) As Integer
' Define locals.
Private disposed As Boolean = False
Private safeHandle As SafeFileHandle
Private bufferSize As Long
Private upperWord As Integer
Public Sub New(filename As String)
If filename Is Nothing Then
Throw New ArgumentNullException("The filename cannot be null.")
Else If filename = ""
Throw New ArgumentException("The filename cannot be an empty string.")
End If
Dim handle As IntPtr = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero)
If handle <> INVALID_HANDLE_VALUE Then
safeHandle = New SafeFileHandle(handle, True)
Else
Throw New FileNotFoundException(String.Format("Cannot open '{0}'", filename))
End If
' Get file size.
bufferSize = GetFileSize(safeHandle, upperWord)
If bufferSize = INVALID_FILE_SIZE Then
bufferSize = -1
Else If upperWord > 0 Then
bufferSize = (CLng(upperWord) << 32) + bufferSize
End If
End Sub
Public ReadOnly Property Size As Long
Get
Return bufferSize
End Get
End Property
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
Usando um identificador seguro para implementar o padrão de descarte para uma classe derivadaUsing a safe handle to implement the dispose pattern for a derived class
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.IO;
using System.Runtime.InteropServices;
using System.Threading;
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);
// Define locals.
private bool disposed = false;
private string filename;
private bool created = false;
private SafeFileHandle safeHandle;
public DisposableStreamResource2(string filename) : base(filename)
{
this.filename = filename;
}
public void WriteFileInfo()
{
if (! created) {
IntPtr hFile = CreateFile(@".\FileInfo.txt", GENERIC_WRITE, 0,
IntPtr.Zero, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
if (hFile != INVALID_HANDLE_VALUE)
safeHandle = new SafeFileHandle(hFile, true);
else
throw new IOException("Unable to create output file.");
created = true;
}
string output = String.Format("{0}: {1:N0} bytes\n", filename, Size);
int bytesWritten;
bool result = WriteFile(safeHandle, output, output.Length, out bytesWritten, IntPtr.Zero);
}
protected override void Dispose(bool disposing)
{
if (disposed) return;
// Release any managed resources here.
if (disposing)
safeHandle.Dispose();
disposed = true;
// Release any unmanaged resources not wrapped by safe handles here.
// 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 filename As String
Private created As Boolean = False
Private safeHandle As SafeFileHandle
Public Sub New(filename As String)
MyBase.New(filename)
Me.filename = filename
End Sub
Public Sub WriteFileInfo()
If Not created Then
Dim hFile As IntPtr = CreateFile(".\FileInfo.txt", GENERIC_WRITE, 0,
IntPtr.Zero, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)
If hFile <> INVALID_HANDLE_VALUE Then
safeHandle = New SafeFileHandle(hFile, True)
Else
Throw New IOException("Unable to create output file.")
End If
created = True
End If
Dim output As String = String.Format("{0}: {1:N0} bytes {2}", filename, Size,
vbCrLf)
WriteFile(safeHandle, output, output.Length, 0&, Nothing)
End Sub
Protected Overloads Overridable 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
Consulte tambémSee also
Comentários
Carregando comentários...