c# inheritance interface idisposable coupling

c# - ¿Cómo debería heredar IDisposable?



inheritance interface (6)

Depende de tu interfaz, pero me inclinaría hacia el n. ° 2. Si tiene dos implementaciones de ISomeInterface y solo una necesita deshacerse de ellas, existe la posibilidad de que necesite refactorizar.

En general, cuando se vincula a una interfaz, es mejor tener esa interfaz heredando IDisposable lugar de la clase base; si su interfaz no hereda IDisposable , debe convertirlo a IDisposable para deshacerse del objeto, y eso corre el riesgo de un InvalidCast ...

Los nombres de clase han sido cambiados para proteger a los inocentes .

Si tengo una interfaz llamada ISomeInterface. También tengo clases que heredan la interfaz, FirstClass y SecondClass. FirstClass utiliza recursos que deben eliminarse. SecondClass no.

Entonces la pregunta es, ¿dónde debería heredar de IDisposable? Ambas opciones siguientes parecen menos que ideales:

1) Hacer que FirstClass herede IDisposable . Entonces, cualquier código que trate con ISomeInterfaces tendrá que saber si deshacerse de ellos o no. Esto huele como un acoplamiento estrecho para mí.

2) Hacer que ISomeInterface herede IDisposable . Entonces, cualquier clase que herede debe implementar IDisposable, incluso si no hay nada que desechar. El método Dispose estaría esencialmente en blanco, excepto por los comentarios.

# 2 parece ser la elección correcta para mí, pero me pregunto si hay alternativas.


Mi consejo es ir a la raíz y no directamente a una clase concreta. El punto 2 está en la raíz y usted está impulsado por algún tipo de contrato por FirstClass. Si sabes que las clases deben implementar alguna interfaz, entonces debes asegurarte de que la interfaz en la que firman un contrato herede IDisposable


Si desea que todo su código trate con ISomeInterfaces genéricamente, entonces sí, todos deben ser desechables.

De lo contrario, el código que crea FirstClass debería eliminarlo:

using (FirstClass foo = new FirstClass()) { someObjectThatWantsISomeInterface.Act(foo); }

de lo contrario, siempre puedes usar algo como este método de extensión:

public static void DisposeIfPossible(this object o) { IDisposable disp = o as IDisposable; if (disp != null) disp.Dispose(); } // ... someObject.DisposeIfPossible(); // extension method on object

También debería mencionar que preferiría un enfoque de clase base de plantilla para esto. Lo apagué en este blog sobre la construcción de cosas desechables correctamente.


Si sabe que algunas implementaciones de ISomeInterface requieren eliminación, entonces la interfaz debe heredar IDisposable, incluso si las implementaciones concretas de la interfaz no tienen nada que desechar.

Por ejemplo, en el BCL, IDataReader implementa IDisposable, aunque uno podría imaginar implementaciones de lector de datos que no tienen recursos externos que deban ser eliminados.


Todas las respuestas escritas hasta ahora omiten un punto clave: solo es necesario para un tipo de base o interfaz base implementar IDisposable si es probable que el código que espera una instancia de clase base pueda adquirir la propiedad de una instancia que requiera su eliminación sin darse cuenta . El escenario más común a través del cual esto puede ocurrir es con un método de fábrica; un buen ejemplo es IEnumerable<T> / IEnumerator<T> . La mayoría de los enumeradores no requieren limpieza, pero el código que llama a IEnumerable<T>.GetEnumerator generalmente no tiene una razón en particular para creer que el enumerador devuelto realmente requerirá limpieza, ni para creer que no lo hará. En general, es más rápido tener todas las implementaciones de IEnumerator<T> implementables como IDisposable , y hacer que todos los consumidores llamen Dispose en el enumerador devuelto, antes que hacer que los consumidores verifiquen si el tipo devuelto implementa IDisposable y llamarlo si es así.

Si se espera que las referencias de tipo base generalmente solo se usarán con métodos que no serán responsables de la limpieza de los elementos en cuestión, no es necesario que el tipo de base implemente IDisposable . El código que sería responsable de la limpieza sabrá que los objetos con los que está IDisposable implementan IDisposable independientemente de si el tipo de base lo hace o no.


Si hay una posibilidad razonable de que una entidad abstracta (interfaz o clase abstracta) deba ser desechable, debe implementarla. Stream , por ejemplo, no necesita IDisposable , ni IEnumerator<T> ...

Una clase base abstracta puede ser más simple, ya que puede tener una implementación predeterminada (vacía) de Dispose() y, posiblemente, el patrón finalizador / Dispose (bool), es decir,

void IDisposable.Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) {} ~BaseType() {Dispose(false);}