Esto es lo que yo entiendo de IDisposable y finalizadores de "CLR a través de C#", "A partir de C#" y otros recursos:Singleton con finalizador pero no IDisposable
- IDisposable es para limpiar administrado y recursos no administrados 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 la fuga de recursos si se olvidan).
Si bien entiendo el razonamiento para y estoy de acuerdo con todo lo anterior, no es un escenario en el que creo que tiene sentido para romper estas reglas: una clase Singleton que es responsable de los recursos no administrados (por ejemplo, proporcionando 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, pero 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?
El hecho es que, si puede concebir un motivo para que su objeto sea reemplazado durante la vida útil de la aplicación, el objeto no puede ser legítimamente un singleton. En cuanto a por qué ... Digamos que agarré el Singleton y lo pasé a las cosas que lo necesitaban (porque, ya sabes, la inyección de dependencia es algo bueno). Entonces algo en algún lugar decide reemplazarlo. Ahora hay * dos singletons * (el anterior que he estado pasando, y el nuevo). Esta misma posibilidad viola la definición completa de Singleton, es decir, ese código siempre ve exactamente una instancia. – cHao
Entonces, antes que nada, santo viejo responde Batman. En segundo lugar, su ejemplo no parece tener sentido.Si pasa una instancia de Singleton a un objeto y luego otro decide que quiere el Singleton, entonces el patrón lo permite; debe obtener una referencia de regreso al objeto que se encuentra actualmente en la memoria. El punto que estaba haciendo era que el patrón no le impide deshacerse del objeto. En ese caso, usando su ejemplo, si el objeto fue eliminado, la instancia única ya no debería existir, por lo que cuando un objeto diferente solicita el Singleton, debería obtener una nueva instancia. –
Si se elimina el objeto, la instancia * does * aún existe; toda persona que la haya adquirido antes de que se haya eliminado aún la tendrá. Por lo tanto, obviamente no se puede convertir en GC, pero ahora no se puede usar. Piensa en las consecuencias de esa afirmación en un contexto multiproceso. Una expresión como 'Singleton.getInstance(). DoStuff()' ya no es segura para hilos, * incluso si tanto 'getInstance' como' doStuff' son *. Podría aparecer un hilo entre las dos llamadas y eliminar la instancia que acabamos de adquirir. Y eso incluso está asumiendo su escenario mítico de todo el mundo-siempre-llama-'getInstance'. – cHao