c# .net singleton dispose

Singleton desechable en C#



.net dispose (8)

Tengo un singleton que usa la "Instancia T de lectura estática = nueva T ();" patrón. Sin embargo, me encontré con un caso en el que T es desechable y, de hecho, debe desecharse para pruebas unitarias. ¿Cómo puedo modificar este patrón para admitir un singleton desechable?

La interfaz que me gustaría es algo así como:

var x = Foo.Instance; var y = Foo.Instance; // x == y ... x.Release(); // this causes the next Foo.Instance to return a fresh object // also, it assumes no further operations on x/y will be performed.

Nota: el patrón tiene que ser seguro para subprocesos, por supuesto.

Editar - a los efectos del código de producción, este es un singleton verdadero. Lo que pasa es que bloquea algunos archivos, por lo que para la limpieza en pruebas unitarias debemos eliminarlo.

También preferiría un patrón que se pueda reutilizar, si es posible.


En ese punto, no creo que realmente lo considere más como un singleton, para ser sincero.

En particular, si un cliente usa un singleton, realmente no van a esperar que tengan que deshacerse de él, y se sorprenderían si alguien más lo hiciera.

¿Qué va a hacer tu código de producción?

EDITAR: Si realmente, realmente necesitas esto para pruebas unitarias y solo para pruebas unitarias (lo cual suena cuestionable en términos de diseño, para ser franco) entonces siempre puedes jugar con el campo usando la reflexión. Sería mejor averiguar si realmente debería ser un singleton o si realmente debería ser desechable: los dos raramente van juntos.


Marque Release como internal y use el atributo InternalsVisibleTo para exponerlo solo al ensamblaje de prueba de su unidad. Puede hacerlo, o si tiene dudas de que alguien de su propia asamblea lo llame, puede marcarlo como private y acceder a él utilizando el reflejo.

Use un finalizador en su singleton que llame al método Dispose en la instancia singleton.

En el código de producción, solo la descarga de un AppDomain causará la eliminación del singleton. En el código de prueba, puede iniciar una llamada para Release .


Para las pruebas unitarias, podría usar una instancia "manual" (pero necesitaría una forma de instanciar el objeto).

En su caso, probablemente sea mejor que use el patrón de fábrica (resumen / método, lo que sea mejor para su caso), combinado con un singleton.

Si desea probar si el singleton se ha desechado correctamente de los objetos usados ​​(en la prueba unitaria), utilice el método Factory, de lo contrario, utilice el patrón singleton.

Por cierto, si no tiene acceso al código fuente de singleton o no tiene permiso para modificarlo, será mejor que lo ajuste a otro singleton y proporcione toda la lógica del nuevo (más parecido a un proxy). Suena excesivo, pero podría ser una solución viable.

Además, para poder controlar el acceso a él, proporcione una fábrica y deje que los clientes obtengan el nuevo objeto solo si el objeto no se ha eliminado.


Puede usar un singleton anclado anidado (Vea aquí ) con algunas modificaciones simples:

public sealed class Singleton : IDisposable { Singleton() { } public static Singleton Instance { get { if (!Nested.released) return Nested.instance; else throw new ObjectDisposedException(); } } public void Dispose() { disposed = true; // Do release stuff here } private bool disposed = false; class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } }

Recuerde lanzar ObjectDisposedException en todos los métodos / propiedades públicos del objeto si se ha eliminado.

También debe proporcionar un método de finalización para el objeto, en caso de que no se llame a Dispose. Vea cómo implementar correctamente IDisposable aquí .


Si la clase implementa IDisposable (como implica que lo hace), simplemente llame a x.Dispose ()


Singletons no debe ser desechable. Período. Si alguien llama a Dispose prematuramente, su aplicación se atornilla hasta que se reinicie.


public class Foo : IDisposable { [ThreadStatic] static Foo _instance = null; private Foo() {IsReleased = false;} public static Foo Instance { get { if (_instance == null) _instance = new Foo(); return _instance; } } public void Release() { IsReleased = true; Foo._instance = null; } void IDisposable.Dispose() { Release(); } public bool IsReleased { get; private set;} }


Otra opción para hacer un Singleton desechable es usar el atributo [Singleton] de SandCastle para su clase, luego Castle framework se encarga de eliminar todos los objetos desechables de Singleton.