recursos method implement how example correctly administrados c# dispose

method - C#Cómo implementar el método Dispose



recursos no administrados c# (3)

Implemento IDisposable

class ConnectionConfiguration:IDisposable { private static volatile IConnection _rbMqconnection; private static readonly object ConnectionLock = new object(); public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } if (_rbMqconnection == null) { return; } lock (ConnectionLock) { if (_rbMqconnection == null) { return; } _rbMqconnection?.Dispose();//double check _rbMqconnection = null; } } }

Necesito un consejo sobre la implementación del método Dispose .

En nuestra aplicación el usuario diseña su propia interfaz de usuario. Tengo una ventana de vista previa que muestra cómo se verá la interfaz de usuario. Todos los objetos dibujados en esta IU derivan finalmente de una clase base común ScreenObject. Mi administrador de vista previa contiene una única referencia de objeto a un ScreenGrid que es el objeto de cuadrícula para el área de vista previa completa.

Pregunta 1

Algunas de mis clases de pantalla derivadas conservan recursos no administrados, como una conexión de base de datos, una imagen de mapa de bits y un control WebBrowser . Estas clases necesitan disponer de estos objetos. ScreenObject un método Dispose virtual en la clase base de ScreenObject base y luego implementé un método Dispose reemplazo en cada una de las clases derivadas que se aferran a recursos no administrados. Sin embargo, en este momento acabo de crear un método llamado Dispose , no estoy implementando IDisposable . ¿Debo implementar IDisposable ? Si es así, ¿cómo lo implemento?

  • Solo en las clases derivadas que tienen recursos no gestionados
  • La clase base y las clases derivadas que tienen recursos no administrados O
  • La clase base y todas las clases derivadas, incluidas aquellas que no tienen recursos no administrados

¿Es incorrecto colocar un método virtual de Dispose en una clase base que no tiene recursos no administrados para que pueda aprovechar el polimorfismo?

Pregunta 2

Al leer sobre el método Dispose y la interfaz IDisposable , Microsoft declara que el objeto de disposición solo debe llamar al método Dispose para su principal. El padre lo llamará por su padre y así sucesivamente. A mí esto me parece al revés. Es posible que desee disponer de un niño pero mantener a su padre cerca.

Pensaría que debería ser al revés, un objeto que se está eliminando debería disponer de sus hijos. Los niños deben disponer de sus hijos y así sucesivamente.

¿Estoy equivocado aquí o me estoy perdiendo algo?


Pregunta 1:

Según los tipos de objetos que enumera (es decir, Base de datos, WebBrowser, Mapa de bits, etc.), estos son solo recursos administrados en lo que respecta a .NET. Por lo tanto, debe implementar IDisposable en cualquier clase que tenga tipos desechables como miembros. Si son instancias declaradas localmente, solo debes llamar ''using ()'' en ellas. Si bien estas instancias que mencionas tienen recursos no administrados, .NET las extrae de ti a través de los tipos que estás utilizando. Como solo está utilizando tipos administrados, debe implementar IDisposable pero sin un finalizador . Solo necesita implementar un finalizador si realmente tiene recursos no administrados como miembros de la clase.

Pregunta 2:

Parece que está confundiendo herencia (es a) con agregación / contención (tiene a). Por ejemplo, si "Contenedor" contiene un recurso desechable como miembro de la clase, se denomina agregación / contención. Por lo tanto, llamar a base.Dispose() en la implementación IDisposable de Container no tiene nada que ver con la eliminación del recurso disponible dentro de Container. Debe recordar que si una clase se deriva de Container, diga "DerivedContainer", que es una instancia de Container aunque con miembros y / o funcionalidad adicionales. Por lo tanto, cualquier instancia de "DerivedContainer" tiene todos los miembros que tiene su clase base "Container". Si nunca llamó a base.Dispose() , el recurso desechable en "Container" no se lanzaría correctamente (en realidad lo haría el GC, pero es una mala práctica por muchas razones simplemente ''dejar que .NET se encargue de ello'') - Consulte mi respuesta publicada en ¿Es una mala práctica depender del recolector de basura automatizado .NET? .

Si no llamó a la clase base Dispose() , terminaría con un objeto parcialmente dispuesto (dispuesto en la clase derivada pero no en la clase base), un escenario muy malo. Por eso es muy importante llamar a la clase base Dispose() .

Tengo un patrón de mejores prácticas que he desarrollado (con mucha experiencia y depuración de volcados de memoria) escrito en mi blog como ejemplo. Muestra cómo implementar IDisposable en una clase base, así como una clase derivada:

http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html


Pregunta 1: Implemente IDisposable también, usando el siguiente patrón:

public class MyClass : IDisposable { bool disposed; protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } } //dispose unmanaged resources disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }

Pregunta 2: Lo que quiere decir Microsoft es que las llamadas de una clase derivada se eliminan en su clase primaria. El propietario de la instancia solo llama a Dispose en el tipo más derivado.

Un ejemplo (acortado):

class Parent : IDisposable { protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } } //dispose unmanaged resources disposed = true; } } class Child : Parent, IDisposable { protected override void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } base.Dispose(disposing); } //dispose unmanaged resources disposed = true; } } class Owner:IDisposable { Child child = new Child(); protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { if(child!=null) { child.Dispose(); } } } //dispose unmanaged ressources disposed = true; } }

El propietario solo llama a Dispose on the Child, pero no a Parent. El niño es responsable de llamar a Dispose sobre el padre.