Domanda

Ho un singleton che usa il "quotato statico in sola lettura T Instance = new T (); " modello. Tuttavia, ho riscontrato un caso in cui T è usa e getta e in realtà deve essere smaltito per i test unitari. Come posso modificare questo modello per supportare un singleton monouso?

L'interfaccia che vorrei è qualcosa del tipo:

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: il modello deve essere sicuro per i thread, ovviamente.

Modifica : ai fini del codice di produzione, questo è un vero singleton. Il fatto è che blocca alcuni file e quindi per la pulizia nei test unitari dobbiamo eliminarli.

Preferirei anche un modello che può essere riutilizzato, se possibile.

È stato utile?

Soluzione

Contrassegnare Rilascio come internal e utilizzare l'attributo InternalsVisibleTo per esporlo solo al gruppo di test delle unità. Puoi farlo, o se diffidare che qualcuno nella tua assemblea lo chiamerà, puoi contrassegnarlo come privato e accedervi usando reflection.

Usa un finalizzatore nel tuo singleton che chiama il metodo Dispose nell'istanza singleton.

Nel codice di produzione, solo lo scarico di un AppDomain provocherà lo smaltimento del singleton. Nel codice di test, puoi avviare una chiamata a Release tu stesso

Altri suggerimenti

A quel punto non credo che lo considererei più un singleton, a dire il vero.

In particolare, se un cliente utilizza un singleton, non si aspetterebbe davvero di doverlo smaltire e sarebbero sorpresi se lo facesse qualcun altro.

Che cosa farà il tuo codice di produzione?

EDIT: se davvero, hai davvero bisogno di questo per i test unitari e solo per i test unitari (che suona discutibile in termini di design, per essere sinceri), puoi sempre giocherellare con il campo usando la riflessione . Sarebbe più bello capire se dovrebbe davvero essere un singleton o se dovrebbe davvero essere usa e getta - i due raramente vanno insieme.

I singoli non devono essere usa e getta. Periodo. Se qualcuno chiama lo smaltimento prematuro, l'applicazione viene avvitata fino al riavvio.

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

  }

Se la classe implementa IDisposable (come intendi), chiama semplicemente x.Dispose ()

Potresti usare un singleton pigro nidificato (Vedi qui ) con alcuni modifiche semplici:

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

Ricorda di lanciare ObjectDisposedException in tutti i metodi / proprietà pubblici dell'oggetto se è stato eliminato.

Dovresti anche fornire un metodo finalizzatore per l'oggetto, nel caso in cui Dispose non venga chiamato. Scopri come implementare correttamente IDisposable qui .

Per i test unitari puoi utilizzare un "manuale" istanza (ma sarebbe necessario un modo per creare un'istanza dell'oggetto).

Nel tuo caso, probabilmente dovresti usare meglio il modello factory (abstract / method - qualunque sia il migliore per il tuo caso), combinato con un singleton.

Se si desidera verificare se il singleton ha eliminato correttamente gli oggetti utilizzati (nel test unitario), utilizzare il metodo Factory, altrimenti utilizzare il modello singleton.

A proposito, se non hai accesso al codice sorgente singleton o non ti è permesso modificarlo, dovresti avvolgerlo in un altro singleton e fornire tutta la logica di quello nuovo (più simile a un proxy). Sembra eccessivo, ma potrebbe essere una soluzione praticabile.

Inoltre, al fine di poter controllare l'accesso ad esso, fornire una factory e lasciare che i client ottengano il nuovo oggetto solo se l'oggetto non è stato eliminato.

Un'altra opzione per creare un Singleton usa e getta è usare l'attributo [Singleton] di SandCastle per la tua classe, quindi il framework Castle si occupa di eliminare tutti gli oggetti Singleton monouso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top