Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

90
Views
¿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 answers
Answer question

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!