Domanda

Esiste questo oggetto simile alla connessione DB di cui avrà bisogno la mia applicazione web. È piuttosto lento da creare e verrà utilizzato raramente, quindi vorrei conservarne solo una singola istanza. Se sono necessarie più richieste contemporaneamente, lock() l'oggetto e serializzerà il loro accesso.

Per rendere le cose più divertenti l'oggetto è un IDisposable e può essere chiuso. Ovviamente, eviterò di scrivere il codice che lo chiude, ma ... sai ... meglio prevenire che curare, vero?

Quindi, l'approccio na & # 239; ve sarebbe quello di implementarlo in questo modo:

private static DBClass _Instance;
private static object _DBLock = new object();

public DBClass GetDB()
{
    if ( _Instance == null )
        lock (_DBLock )
            if ( _Instance == null )
                _Instance = CreateInstance();
    lock (_Instance)
        if ( _Instance.Disposed )
            _Instance = CreateInstance();
    return _Instance;
}

Verrà quindi utilizzato come:

lock (var Conn = Global.GetDB() )
{
    // Use Conn here.
}

Probabilmente funzionerà per la maggior parte del tempo, ma vedo un'apertura che potrebbe essere sfruttata: se due thread lo chiamano contemporaneamente, ottengono la stessa istanza allo stesso tempo e quindi si potrebbe ancora Dispose() prima che l'altro acquisisca un Disposed su di esso. Pertanto, il codice successivo non riesce. Anche il controllo di <=> in ogni luogo che lo utilizza sembra imbarazzante. In effetti, <=> ing sembra troppo imbarazzante, ma l'istanza non è intrinsecamente sicura per i thread, quindi non c'è niente che io possa fare al riguardo.

Come lo implementeresti?

È stato utile?

Soluzione

Per cominciare, suggerirei di evitare un doppio controllo. È molto facile sbagliare, come hai fatto in questo caso, non rendendo la variabile volatile.

Dato che non si desidera effettivamente disporre l'oggetto, c'è motivo di non avvolgerlo in qualcosa che implementa la stessa API ma senza esporre lo smaltimento? In questo modo potresti anche incapsulare il blocco, potenzialmente, a seconda di come usi effettivamente l'oggetto. Un altro modo per farlo sarebbe quello di esporre un'API in termini di Action<DBClass>: si passa all'azione che si desidera intraprendere con l'oggetto e l'helper si occupa di creare l'istanza e bloccare in modo appropriato.

Un ultimo punto: tutto ciò sembra un po 'complicato in termini di testabilità. Non so se sei un fan dei test unitari, ecc., Ma i singoli spesso rendono la vita un po 'imbarazzante per i test.

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