c# .net singleton idisposable

c# - Singleton con finalizador pero no IDisposable



.net (6)

Aplicabilidad de Singleton a cualquier situación particular aparte,

Creo que no hay nada malo con Disposing of Singleton. En combinación con la creación de instancias perezosas, solo significa que libera recursos si no los necesita temporalmente y luego vuelve a adquirirlos según sea necesario.

Esto es lo que entiendo sobre IDisposable y finalizadores de "CLR via C #", "Effective C #" y otros recursos:

  • IDisposable es para limpiar recursos gestionados y no gestionados de forma determinista.
  • Las clases que son responsables de recursos no administrados (por ejemplo, identificadores de archivos) deben implementar IDisposable y proporcionar un finalizador para garantizar que se limpien incluso si el código del cliente no llama a Dispose () en la instancia.
  • Las clases que son responsables de los recursos administrados solo nunca deben implementar un finalizador.
  • Si tiene un finalizador, debe implementar IDisposable (esto permite que el código del cliente haga lo correcto y llame a Dispose (), mientras que el finalizador evita que se filtren recursos si se olvidan).

Si bien entiendo el razonamiento y estoy de acuerdo con todo lo anterior, hay un escenario en el que creo que tiene sentido romper estas reglas: una clase única que es responsable de los recursos no administrados (como proporcionar un único punto de acceso a archivos particulares) )

Creo que siempre es incorrecto tener un método Dispose () en un singleton porque la instancia singleton debería vivir durante la vida de la aplicación y si algún código del cliente llama a Dispose (), entonces está lleno. Sin embargo, desea un finalizador para que cuando la aplicación se descargue, el finalizador pueda limpiar los recursos no administrados.

Así que tener una clase singleton con un finalizador que no implementa IDisposable me parece una opción razonable, sin embargo, este tipo de diseño es contrario a lo que entiendo son las mejores prácticas.

¿Es este un enfoque razonable? Si no, ¿por qué no y cuáles son las alternativas superiores?


Primero mencionaré que los patrones de diseño orientados a objetos y sus consecuencias no siempre influyen en cada decisión de lenguaje, incluso en lenguajes orientados a objetos. Sin duda, puede encontrar patrones de diseño clásicos que son más fáciles de implementar en un idioma (Smalltalk) en lugar de otro (C ++).

Dicho esto, no estoy seguro de estar de acuerdo con la premisa de que una instancia singleton solo debería eliminarse al final de una aplicación. Nada en las descripciones de patrones de diseño que he leído para Singleton (o Patrones de diseño: elementos del software reutilizable orientado a objetos ) menciona esto como una propiedad de este patrón. Un singleton debería asegurar que solo existe una instancia de la clase en cualquier momento en el tiempo; eso no implica que deba existir mientras exista la aplicación.

Tengo la sensación de que, en la práctica, existen muchos singletons durante la mayor parte de la vida útil de una aplicación. Sin embargo, considere una aplicación que utiliza una conexión TCP para comunicarse con un servidor, pero también puede existir en un modo desconectado. Cuando esté conectado, deseará que un singleton mantenga la información de conexión y el estado de la conexión. Una vez desconectado, es posible que desee conservar ese mismo singleton o puede deshacerse del singleton. Mientras que algunos pueden argumentar que tiene más sentido mantener el singleton (e incluso puedo estar entre ellos), no hay nada en el patrón de diseño que impida que usted se deshaga de él. Si se rehace una conexión, se puede instanciar el singleton. de nuevo, ya que no existe ninguna instancia de eso en ese momento.

En otras palabras, puede crear escenarios en los que es lógico que los singleton tengan IDisposable.


Si bien puede obtener críticas de revisión de código y advertencias de FxCop, no hay nada intrínsecamente incorrecto al implementar un finalizador sin IDisposable. Sin embargo, hacerlo en un singleton no es una forma confiable de capturar procesos o eliminación de AppDomain.

A riesgo de ofrecer consejos de diseño subjetivos: si el objeto es verdaderamente sin estado, conviértalo en una clase estática. Si es con estado, pregunta por qué es un Singleton: estás creando una variable global mutable. Si intenta capturar aplicaciones cerradas, trate con ellas cuando salga su bucle principal.


Si el recurso no administrado se lanza solo al salir de la aplicación, ni siquiera tiene que preocuparse por un finalizador, ya que la descarga del proceso debería ocuparse de esto de todos modos.

Si tiene varios dominios de aplicación y desea lidiar con la descarga de un dominio de aplicación, ese es un problema posible, pero posiblemente uno que no necesita preocuparse.

En segundo lugar los que dicen que este diseño posiblemente no sea el correcto (y dificultará la reparación es que posteriormente encuentras que realmente necesitas dos instancias) Crea el objeto (o un objeto de envoltura de carga lenta) en tu punto de entrada y pasarlo por el código hasta donde sea necesario para dejar en claro quién es el responsable de proporcionarlo a quién, entonces usted es libre de cambiar la decisión de usar solo uno con poco efecto para el resto del código (que usa lo que obtiene dado)


Siempre que su finalizador no invoque métodos (como Dispose) en ningún otro objeto administrado, debería estar bien. Solo recuerde que el orden de finalización no es determinista. Es decir, si su objeto singleton Foo contiene una referencia a la barra de objeto que requiere eliminación, no puede escribir confiablemente:

~Foo() { Bar.Dispose(); }

El recolector de basura podría haber recogido Bar ya.

A riesgo de entrar en una pila de OO goo (es decir, comenzar una guerra), una alternativa al uso de un singleton es usar una clase estática.


Si desea crear un singleton con un finalizador, probablemente debería tener la referencia estática para que sea una WeakReference. Esto requerirá un poco de trabajo adicional para garantizar la seguridad del hilo en el acceso, pero permitirá que el singleton sea recogido cuando nadie lo esté utilizando (si alguien llama posteriormente al método GetInstance (), obtendrán un nueva instancia). Si se utilizara una referencia fuerte estática, mantendría activa la instancia de singleton incluso si no hubiera otras referencias a ella.