C# Avanzado: Stream de Archivos con Dispose y Finalize
Cuando trabajamos con archivos en C#, es fundamental liberar los recursos correctamente para evitar fugas, bloqueos o problemas de rendimiento.
Cuando trabajas con archivos en C#, una mala gestión de recursos puede causarte más problemas de los que imaginas: 🔒 archivos bloqueados, errores al acceder desde otros procesos ⚠️ o consumo innecesario de memoria 🐏.
¿Qué es lo ideal?
Crear una clase que:
Abra y lea archivos de texto
Implemente el patrón
IDisposable
para liberar recursos de forma deterministaUse un destructor (Finalize) como respaldo en caso de que olvides llamar a
Dispose
Diferencia entre Dispose y Finalize
🔄 Dispose
Es un método que implementas al usar la interfaz
IDisposable
.Permite liberar recursos de forma explícita y controlada (como archivos, conexiones, streams).
Se llama manualmente o mediante un bloque
using
.Proporciona un momento determinista para liberar recursos.
🛑 Finalize
Es un método especial (destructor en C#) invocado automáticamente por el recolector de basura.
Se usa para liberar recursos no administrados si
Dispose
no fue llamado.Se ejecuta en un momento no determinístico, cuando el GC recolecta el objeto.
No se recomienda depender exclusivamente de él para liberar recursos críticos.
Ejemplo práctico: clase FileReader
public class FileReader : IDisposable
{
private StreamReader _reader;
private bool _disposed = false;
public FileReader(string path)
{
_reader = new StreamReader(path);
}
public string ReadAll()
{
if (_disposed)
throw new ObjectDisposedException(nameof(FileReader));
return _reader.ReadToEnd();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_reader?.Dispose();
}
_disposed = true;
}
}
~FileReader()
{
Dispose(false);
}
}
Explicación del código:
private StreamReader _reader;
Almacena la instancia deStreamReader
que se usa para leer el archivo.private bool _disposed = false;
Indica si los recursos ya fueron liberados para evitar operaciones posteriores.Constructor
FileReader(string path)
Abre el archivo para lectura inicializando elStreamReader
.Método
ReadAll()
Lee todo el contenido del archivo. Antes, verifica que la instancia no haya sido ya liberada (_disposed
) para evitar errores.Método público
Dispose()
Llama a la sobrecargaDispose(bool disposing)
contrue
, indicando que la liberación es explícita, y luego evita que el recolector de basura llame al destructor conGC.SuppressFinalize(this)
.Método protegido
Dispose(bool disposing)
Sidisposing
estrue
, libera los recursos administrados, en este caso elStreamReader
. También establece_disposed
entrue
para marcar que los recursos ya fueron liberados.Destructor
~FileReader()
Este método es la representación en C# del métodoFinalize
.
El recolector de basura (GC) lo invoca automáticamente cuando detecta que el objetoFileReader
está listo para ser recolectado, y sólo si no se llamó previamente aDispose()
.
En este destructor se llama aDispose(false)
, liberando únicamente recursos no administrados como respaldo.
Cómo usarla correctamente
using (var fileReader = new FileReader("archivo.txt"))
{
string contenido = fileReader.ReadAll();
Console.WriteLine(contenido);
}
Al salir del bloque using
, se llama automáticamente a Dispose()
, liberando el archivo y cualquier otro recurso.
Forma incorrecta de usar FileReader
var fileReader = new FileReader("archivo.txt");
string contenido = fileReader.ReadAll();
// No se llama a Dispose() ni se usa 'using'
¿Por qué no usar esta forma?
El archivo permanece abierto hasta que el recolector de basura finalice el objeto, lo que puede tardar un tiempo indefinido.
Puede causar bloqueos y fugas de recursos.
No hay liberación determinista de los recursos.
Consejo final
Siempre usa using
o llama explícitamente a Dispose()
cuando trabajes con recursos externos como archivos, bases de datos o conexiones.
Esto mejora la estabilidad y rendimiento de tus aplicaciones.
🚀 Da el siguiente paso en www.netuniversity.org
👨💻 ¡Conviértete en un desarrollador .NET completo que escribe código eficiente y profesional
!