Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.
El uso principal de la IDisposable interfaz es liberar recursos no administrados. El recolector de elementos no utilizados libera automáticamente la memoria asignada a un objeto administrado cuando ese objeto ya no se usa. Sin embargo, no es posible predecir cuándo se producirá la recolección de basura. Además, el recolector de basura no tiene conocimiento de recursos no administrados, como identificadores de ventana o archivos y flujos abiertos.
Usa el Dispose método de esta interfaz para liberar explícitamente recursos no administrados junto con el recolector de basura. El consumidor de un objeto puede llamar a este método cuando el objeto ya no es necesario.
Advertencia
Se trata de un cambio importante para agregar la IDisposable interfaz a una clase existente. Dado que los consumidores preexistentes de su tipo no pueden llamar a Dispose, no puede estar seguro de que se liberarán los recursos no administrados que posee su tipo.
Dado que se llama a la implementación de IDisposable.Dispose por parte de un consumidor de un tipo cuando los recursos que pertenecen a una instancia ya no son necesarios, debe encapsular el objeto administrado en un SafeHandle (la alternativa recomendada) o debe sobrescribir Object.Finalize para liberar recursos no administrados en caso de que el consumidor olvide llamar a Dispose.
Importante
En .NET Framework, el compilador de C++ admite la eliminación determinista de recursos y no permite la implementación directa del Dispose método.
Para obtener una explicación detallada sobre cómo se usa esta interfaz y el método Object.Finalize, consulte los temas Recolección de elementos no utilizados e Implementación de un método Dispose.
Usa un objeto que implemente IDisposable
Si la aplicación simplemente usa un objeto que implementa la IDisposable interfaz, debe llamar a la implementación del IDisposable.Dispose objeto cuando haya terminado de usarlo. En función del lenguaje de programación, puede hacerlo de una de estas dos maneras:
- Mediante una estructura de lenguaje como la instrucción
using
en C# y Visual Basic, y la instrucciónuse
o la funciónusing
en F#. - Ajustando la llamada a la implementación de IDisposable.Dispose en un bloque
try
/finally
.
Nota:
La documentación de los tipos que implementan IDisposable tiene en cuenta este hecho e incluye un recordatorio para llamar a su implementación de Dispose.
Instrucción Using de C#, F#y Visual Basic
Si el lenguaje admite una construcción como la instrucción using en C#, la instrucción Using en Visual Basic o la instrucción use en F#, puede usarla en lugar de llamarse IDisposable.Dispose explícitamente. En el ejemplo siguiente se usa este enfoque para definir una WordCount
clase que conserva información sobre un archivo y el número de palabras que hay en él.
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
using (StreamReader sr = new StreamReader(filename))
{
txt = sr.ReadToEnd();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
use sr = new StreamReader(filename)
sr.ReadToEnd()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Using sr As New StreamReader(filename)
txt = sr.ReadToEnd()
End Using
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
La instrucción using
(expresión use
en F#) es realmente una comodidad sintáctica. En tiempo de compilación, el compilador de lenguaje implementa el lenguaje intermedio (IL) para un try
/finally
bloque.
Para obtener más información sobre la instrucción using
, consulte los temas Instrucción Using o Instrucción using.
Bloque Try/Finally
Si el lenguaje de programación no admite una construcción como la using
instrucción en C# o Visual Basic, o la use
instrucción en F#, o si prefiere no usarla, puede llamar a la IDisposable.Dispose implementación desde el finally
bloque de una try
/finally
instrucción. En el ejemplo siguiente se reemplaza el using
bloque del ejemplo anterior por un try
/finally
bloque .
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount2
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount2(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
StreamReader? sr = null;
try
{
sr = new StreamReader(filename);
txt = sr.ReadToEnd();
}
finally
{
if (sr != null) sr.Dispose();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount2(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
let sr = new StreamReader(filename)
try
sr.ReadToEnd()
finally
sr.Dispose()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount2
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Dim sr As StreamReader = Nothing
Try
sr = New StreamReader(filename)
txt = sr.ReadToEnd()
Finally
If sr IsNot Nothing Then sr.Dispose()
End Try
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
Para obtener más información sobre el patrón try
/finally
, consulte Instrucción Try...Catch...Finally, try-finally, Expresión try...finally o Instrucción try-finally.
Implementación de IDisposable
Debe implementar IDisposable si su tipo utiliza directamente recursos no administrados o si desea aprovechar recursos desechables usted mismo. Los consumidores del tipo pueden llamar a la implementación de IDisposable.Dispose para liberar recursos cuando ya no se necesite la instancia. Para controlar los casos en los que no pueden llamar a Dispose, debe usar una clase derivada de SafeHandle para encapsular los recursos no administrados, o bien debe invalidar el método Object.Finalize para un tipo de referencia. En cualquier caso, se usa el Dispose método para realizar cualquier limpieza necesaria después de usar los recursos no administrados, como su liberación, eliminación o restablecimiento. Para obtener más información sobre la implementación de IDisposable.Dispose, consulte la sobrecarga del método Dispose(bool).
Importante
Si va a definir una clase base que usa recursos no administrados y que tiene, o es probable que tenga, subclases que se deben eliminar, debe implementar el IDisposable.Dispose método y proporcionar una segunda sobrecarga de Dispose
, como se describe en la sección siguiente.
IDisposable y la jerarquía de herencia
Una clase base con subclases que debe ser descartable debe implementar IDisposable de la siguiente manera. Debe usar este patrón siempre que implemente IDisposable en cualquier tipo que no sea sealed
(NotInheritable
en Visual Basic).
- Debe proporcionar un método público, no virtual Dispose() y un método virtual
Dispose(Boolean disposing)
protegido. - El Dispose() método debe llamar a
Dispose(true)
y debería suprimir la finalización para mejorar el rendimiento. - El tipo base no debe incluir ningún finalizador.
El siguiente fragmento de código refleja el patrón dispose para las clases base. Se supone que el tipo no invalida el método Object.Finalize.
using System;
using System.IO;
using System.Runtime.InteropServices;
class BaseClass1 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
disposed = true;
}
}
open System
open System.IO
type BaseClass1() =
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
disposed <- true
Imports System.IO
Imports System.Runtime.InteropServices
Class BaseClass1 : Implements IDisposable
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=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
fs.Dispose()
' Free any other managed objects here.
'
End If
disposed = True
End Sub
End Class
Si reemplaza el Object.Finalize método , la clase debe implementar el siguiente patrón.
using System;
class BaseClass2 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: 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;
}
~BaseClass2()
{
Dispose(disposing: false);
}
}
open System
type BaseClass2() =
// Flag: Has Dispose already been called?
let mutable disposed = false
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
// Free any other managed objects here.
()
// Free any unmanaged objects here.
disposed <- true
override this.Finalize() =
this.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(disposing:=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(disposing:=False)
End Sub
End Class
Las subclases deben implementar el patrón desechable de la siguiente forma:
- Deben invalidar
Dispose(Boolean)
y llamar a la implementaciónDispose(Boolean)
de la clase base. - Pueden proporcionar un finalizador si es necesario. El finalizador debe llamar a
Dispose(false)
.
Tenga en cuenta que las clases derivadas no implementan la IDisposable interfaz y no incluyen un método sin Dispose parámetros. Solo invalidan el método de clase Dispose(Boolean)
base.
El fragmento de código siguiente refleja el patrón dispose para las clases derivadas. Se supone que el tipo no invalida el método Object.Finalize.
using System;
using System.IO;
using System.Runtime.InteropServices;
class MyDerivedClass : MyBaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
open Microsoft.Win32.SafeHandles
open System
type MyDerivedClass() =
inherit MyBaseClass()
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
// Implementation of Dispose pattern.
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
// Free any unmanaged objects here.
disposed <- true
// Call base class implementation.
base.Dispose disposing
Imports System.IO
Imports System.Runtime.InteropServices
Class DerivedClass2 : Inherits BaseClass2
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
fs.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