2010-12-30 9 views
5
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 gestire questo tipo di situazione per garantire che vengano chiamate le istanze disposte all'interno della classe? (Non v'è alcun segnale per i chiamanti che devono chiamare 'Chiudi' tranne nella documentazione.) Le implementazioni di IMyInterface non necessariamente incapsulano le istanze IDisposible e vengono chiusi e riaperti più volte per tutta la vita dell'applicazione.Come affrontare con una classe che incapsula un'istanza disposible?

Sto pensando di fare questo:

  • Implementare IDisposible in MyImplementation.
  • Set Dispose() per chiamare Close().
  • Aggiungere una chiamata a Close() o Dispose() all'opzione di Open per garantire che la precedente chiamata sia stata chiusa.

Gli utenti di IMyInterface non sanno cosa implementazione che stanno utilizzando, quindi non sono sicuro di quanto valore rendendo MyImplementation disposible ha, e ancora una volta, non tutte le implementazioni incapsulare IDisposibles.

risposta

1

Oltre alle risposte già qui:

Se questa classe è (spesso/a volte) utilizzato tramite l'interfaccia da solo consiglierei di ereditare IMyInterace da IDisposable.

Ciò consentirà agli utenti di utilizzare questi oggetti in modo coerente. Lo svantaggio è che potrebbe essere necessario aggiungere (fittizio) metodi Dispose a classi che non ne hanno effettivamente bisogno. Ma il vantaggio è in coerenza e flessibilità: cosa succede se una classe cambia in futuro in modo che abbia bisogno di un Dispose()?

Un approccio minimale:

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 

} 
5

Il modo standard per gestire questo è semplicemente avere MyImplementation implementare IDisposable.

3

Come ha detto John, il tuo primo punto elenco è giusto.

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

Il punto di punto 3 non è necessariamente applicabile, poiché un oggetto disposto non deve essere riutilizzato. Se avete bisogno di chiamare Open() ancora una volta, è necessario utilizzare una nuova istanza. Infatti, il metodo Open() dovrebbe generare un valore ObjectDisposedException una volta chiamato (controllando una bandiera booleana privata disposed). Se si desidera che l'oggetto per supportare riapertura dopo la chiusura, si potrebbe considerare l'utilizzo di Debug.Assert() e/o un'eccezione se Open() è chiamato senza Close(). Ciò contribuirà a prevenire la gestione scorretta di queste istanze.

Assicurarsi di seguire il modello usa e getta piena, che è più complicato 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; 
} 
+2

Non è necessario il modello usa e getta pieno.Non c'è bisogno di un distruttore e quindi non di SuppressFinalize. –

Problemi correlati