Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

89
Vistas
¿El patrón IDisposable de Microsoft es realmente correcto?

Me he topado con la forma recomendada por Microsoft de implementar el patrón IDisposable muchas veces, incluso está presente en Visual Studio como una opción de "Implementar interfaz" en el menú del ícono de la lámpara. Se parece a esto:

 // Override only if 'Dispose(bool disposing)' has code to free unmanaged resources ~Foo() { // Do not change this code. Dispose(calledByFinalizer: true); }
 public void Dispose() { // Do not change this code. Dispose(calledByFinalizer: false); GC.SuppressFinalize(this); }
 // Put cleanup code here protected virtual void Dispose(bool calledByFinalizer) { if (_disposed) return; if (!calledByFinalizer) { /* dispose managed objects */ } /* free unmanaged resources and set large fields to null */ _disposed = true; }

Refactoricé un poco el código sugerido (porque Dispose(disposición bool) puede romper el cerebro de alguien, y anidado si puede romper los ojos de alguien).

Pero todavía tengo algunas preguntas en mi mente:

  1. Se supone que el método se llamará una vez. Entonces, ¿por qué se _disposed = true al final del método y no al principio? Si se llama a IDisposable.Dispose() desde diferentes subprocesos, entonces todos pueden omitir el if (_disposed) return; verifique y ejecute el cuerpo del método dos veces. ¿Por qué no hacerlo así?
 if (_disposed) return; else _disposed = true;
  1. ¿Por qué protected virtual void Dispose(bool disposing) está marcado como virtual ? Cualquier clase derivada no tiene acceso al campo _disposed y puede romper fácilmente su comportamiento. Solo podemos marcar como virtual la parte opcional donde la clase derivada puede hacer cualquier cosa sin llamar a base.Dispose() :
 ~Foo() => FreeUnmanagedResources(); public void Dispose() { if (_disposed) return; else _disposed = true; DisposeManagedObjects(); FreeUnmanagedResources(); GC.SuppressFinalize(this); } protected virtual void DisposeManagedObjects() { } protected virtual void FreeUnmanagedResources() { }
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

  1. No puede asumir que Dispose solo será llamado una vez. En las mejores prácticas, sí. En la peor práctica, en absoluto. Cada situación no puede usar convenientemente una declaración de using . Entonces, en lugar de arriesgarse a que el código intente limpiar los recursos no administrados dos veces, lo que podría salir muy mal, según el tipo de recurso, se agregó una bandera que lo impide. Esto elimina la carga del código de llamada en cuanto a recordar si ya se ha llamado a dispose .

  2. Dispose debe declararse como virtual para admitir cualquier limpieza por separado que pueda ser necesaria si se crean subclases que crean instancias de recursos no administrados que son claramente diferentes a los que se usan en la clase base. Dispose en la subclase debe llamar a base.Dispose(); antes o después de que limpie su propio desorden.

over 4 years ago · Santiago Trujillo Denunciar

0

El patrón es correcto, pero asume el peor de los casos, donde también debe implementar un finalizador. Es decir, si necesitas un finalizador también debes seguir todo el patrón. Sin embargo...

Por lo general, no necesita un finalizador en absoluto.

Solo necesita un finalizador si está creando el contenedor administrado original para un recurso no administrado.

Por ejemplo, supongamos que crea un nuevo sistema de base de datos nunca antes visto. Desea proporcionar un proveedor .Net ADO para este nuevo tipo de base de datos, incluidas las conexiones (se heredará de Dbconnection). Las operaciones de red subyacentes aquí serán un recurso no administrado y aún no hay un finalizador para liberarlas en ninguna parte de su árbol de herencia. Por lo tanto, debe implementar su propio finalizador.

Por otro lado, si está creando un objeto contenedor para que su aplicación administre las conexiones a un tipo de base de datos existente, simplemente reempaquetando (envolviendo o heredando) una SqlConnection, OleDbConnection, MySqlConnection, etc. existente, entonces aún debe implementar IDisposable, pero no ya es un finalizador provisto para el recurso no administrado y no necesita escribir otro.

Y resulta que, cuando no tiene un finalizador, puede eliminar con seguridad gran parte del código del patrón IDisposable documentado.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda