Pregunta

Tengo un singleton que usa la instancia estática de solo lectura T = = T nueva (); " modelo. Sin embargo, me encontré con un caso en el que T es desechable, y en realidad necesita ser desechado para pruebas de unidad. ¿Cómo puedo modificar este patrón para admitir un singleton desechable?

La interfaz que me gustaría es algo 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 debe ser seguro para subprocesos, por supuesto.

Editar : para el propósito del código de producción, este es un verdadero singleton. La cosa es que bloquea algunos archivos, y para la limpieza en las pruebas unitarias tenemos que eliminarlos.

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

¿Fue útil?

Solución

Marque Release como interno y use el atributo InternalsVisibleTo para exponerlo solo a su ensamble de prueba de unidad. Puede hacerlo o, si tiene dudas, alguien de su propio ensamblaje lo llamará, puede marcarlo como private y acceder a él mediante la reflexión.

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

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

Otros consejos

En ese momento, no creo que realmente lo considere un singleton más, para ser honesto.

En particular, si un cliente usa un singleton realmente no va a esperar que tenga 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 necesita esto para las pruebas unitarias y solo para las pruebas unitarias (lo que suena cuestionable en términos de diseño, para ser franco), siempre puede jugar con el campo utilizando la reflexión. . Sería mejor averiguar si debería realmente ser un singleton o si debería realmente ser desechable; los dos rara vez van de la mano.

Los Singletons no deben ser Desechables. Período. Si alguien llama Desechar prematuramente, su aplicación se atornilla hasta que se reinicia.

 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;}

  }

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

Puede usar un singleton perezoso anidado (consulte aquí ) con algunos 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 la excepción ObjectDisposedException en todos los métodos / propiedades públicos del objeto si se ha eliminado.

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

Para las pruebas unitarias, puede usar un " manual " instancia (pero necesitaría una forma de crear una instancia del objeto).

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

Si desea probar si el singleton ha eliminado adecuadamente los objetos usados ??(en la prueba de unidad), use el método de Fábrica, de lo contrario, use el patrón de singleton.

Por cierto, si no tiene acceso al código fuente de singleton o no tiene permiso para modificarlo, es mejor envolverlo en otro singleton y proporcionar toda la lógica de la nueva (más como un apoderado). Suena como una exageración, pero podría ser una solución viable.

También, para poder controlar el acceso, proporcionar una fábrica y permitir que los clientes obtengan el nuevo objeto solo si el objeto no se ha eliminado.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top