Domanda

interface IMyInterace
{
void Open();
object Read();
void Close();
}

class MyImplementation : IMyInterface
{
public void Open() { /* instantiates disposible class */ }
//...
public void Close() { /* calls .Dispose(); */ }

}

C'è un buon modo per affrontare questo tipo di situazione per garantire che le istanze disposible all'interno della classe di ottenere chiamato? (Non v'è alcun segnale per i chiamanti che devono chiamare 'Chiudi' tranne nella documentazione.) Le implementazioni di IMyInterface non necessariamente istanze incapsulare IDisposible e vengono chiusi e riaperti più volte per tutta la vita dell'applicazione.

Sto pensando di fare questo:

  • Implementare IDisposible in MyImplementation.
  • Imposta Dispose () per chiamare Close ().
  • Aggiungi una chiamata a Close () o Dispose () per la Inizio di aperto per assicurare precedente chiamata è stata chiusa.

Gli utenti di IMyInterface non so cosa implementazione che stanno utilizzando, quindi non sono sicuro di come valore molto più grandi che MyImplementation disposible ha, e ancora una volta, non tutte le implementazioni incapsulare IDisposibles.

È stato utile?

Soluzione

In aggiunta alle risposte già qui:

Se questa classe è (spesso / a volte) utilizzata attraverso l'interfaccia da solo vorrei consigli per IMyInterace ereditare da IDisposable.

che permetterà agli utenti di utilizzare questi oggetti in modo coerente. Lo svantaggio è, naturalmente, che potrebbe essere necessario aggiungere (fittizie) METODI DI SMALTIMENTO alle classi che in realtà non ne hanno bisogno. Ma il vantaggio è nella consistenza e flessibilità: Che cosa succede se una classe cambia in futuro, in modo che non ha bisogno di un Dispose ()

?

Un approccio minimal:

interface IMyInterace : IDisposable { }

sealed class MyImplementation : IMyInterface 
{   
   public void Open() { /* instantiates disposible class */ }

   public void Close() { /* calls _myField.Dispose(); */ }

   public void Dispose() { Close(); }  // only use this short form in a sealed class

}

Altri suggerimenti

Il metodo standard per gestire questa situazione è quello di avere semplicemente MyImplementation implementare IDisposable.

Come John accennato, il tuo primo punto è proprio sulla.

A volte un metodo Close() è funzionalmente sinonimo di Dispose(), ed esiste per mantenere la coerenza semantica con un'astrazione. Che è, per completare un metodo Open(). Altre volte, Close() vi permetterà di ri-aperto, ma Dispose() non dovrebbe. Il tuo secondo punto-punto è quindi bene, pure.

pallottola punto 3 non è necessariamente applicabile, poiché un oggetto eliminato non deve essere riutilizzato. Se avete bisogno di chiamare Open() ancora una volta, è necessario utilizzare una nuova istanza. In realtà, il metodo Open() dovrebbe lanciare un ObjectDisposedException volta Dispose() sono stati chiamati (controllando un disposed privato flag booleano). Se si desidera che l'oggetto al supporto riapertura dopo la chiusura, si potrebbe considerare l'utilizzo di Debug.Assert() e / o un'eccezione se Open() viene chiamato senza Close(). Questo aiuterà a prevenire la gestione sciatta di questi casi.

Assicurati di seguire il modello usa e getta piena, che è più coinvolto che semplicemente implementando l'interfaccia:

bool disposed;

public void Dispose() // don't make virtual!
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if(!disposed)
    {
        if(disposing) 
        {
            // dispose of managed resources here, for example:
            // if(resource != null) { resource.Dispose(); } 
        }
    }

    // dispose of unmanaged resources here 

    disposed = true;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top