2009-11-20 9 views
13

Come sviluppatore Java che entra in .NET Mi piacerebbe capire l'interfaccia IDisposable. Qualcuno potrebbe tentare di spiegare questo e come si differenzia da ciò che accade in Java? Grazie.Metafora identificabile in Java?

risposta

17

Ho scritto un detailed series of articles on IDisposable.

L'idea di base è che a volte si ha bisogno di disporre in modo deterministico delle risorse. IDisposable fornisce quel meccanismo.

Ad esempio, supponiamo di avere un controllo in una finestra. Quando viene creato, crea internamente un handle di Windows (HWND). Quando rimuovi il controllo dalla finestra e non viene più utilizzato, il controllo diventa idoneo per la garbage collection, ma non viene raccolto immediatamente. In realtà, non ci sono garanzie su quanto tempo ci vorrà prima che venga raccolto.

Fino a quando il GC non esegue e elabora il controllo orfano, continuerà a utilizzare le risorse, poiché mantiene ancora l'HWND.

IDisposable fornisce un mezzo per oggetti che contengono codice che richiede la pulizia separata dal GC per essere esplicitamente ripulito dall'utente dell'oggetto. Nel caso del controllo, possiamo chiamare myControl.Dispose(), che immediatamente pulirà in modo sincrono le risorse "native" (HWND) utilizzate dal controllo.

+2

Domanda veloce: come si può sapere se una risorsa non è gestita e deve essere disposta in modo esplicito? – gil

+3

Vedere se implementa IDisposable. :) Quasi sempre disponga i tuoi IDisposables, se puoi. –

+0

Se la risorsa non è gestita, è necessario conoscerla solo quando si implementa la classe. Se non lo stai implementando, ma semplicemente utilizzandolo, non è necessario prestare particolare attenzione. Se è necessario decidere sullo smaltimento esplicito, provare a rispondere alla domanda "Rilasciare la risorsa ASAP è più critico rispetto all'esecuzione continua in questo thread in questo momento". Le risposte possono essere diverse per esempio per porzione di servizio web o porzione di GUI. –

-3

Non c'è alcun equivalente.

Viene utilizzato quando si utilizzano risorse non gestite (in Java tutte le risorse gestite).

Nella memoria .net allocata dalle risorse gestite viene raccolta automaticamente dal GC (come in Java).

Hai inoltre la possibilità di utilizzare risorse non gestite, dove sarai responsabile per l'allocazione della memoria e il suo rilascio.

Si chiama questo metodo quando non si ha più bisogno delle risorse.

7

Ci sono situazioni in cui è necessario uno smaltimento affidabile per le risorse di proprietà della classe. Ad esempio, la connessione aperta deve essere chiusa in tempo utile, non quando GC decide di raccogliere memoria. Nel metodo .NET Dispose viene utilizzato dalla convenzione per questo. Può essere chiamato in try ... finally blocco, ad esempio:

IConnection conn = OpenConnection(); 
try{ 
    ... 
}finally{ 
    conn.Dispose(); 
} 

Poiché questo modello è così ampiamente usato, c'è un surrogato di questo:

using(IConnection conn = OpenConnection()){ 
} // Dispose is called at the end. 

Poiché questa sintassi è molto concisa, talvolta è utile implementare IDisposable su oggetti che non possiedono risorse, ma devono essere eseguite al termine dell'utilizzo. Per esempio. considerare classe

class TimeMeasure: IDisposable{ 
    public void Measure(string operation) { ... } // recourds operation time 
    public void Dispose(){ 
     ... // print timings for all operations 
    } 
} 

Usage:

using(TimeMeasure m = new TimeMeasure()) 
{ 
    DoFoo(); 
    m.Measure("Foo"); 
    DoBar(); 
    m.Measure("Bar"); 
} // timings for 'Foo' and 'Bar' are printed here 

In Java un'interfaccia più o meno equivalente è Closeable. Ma non esiste una sintassi semplice per garantire le sue chiamate.

Come deve essere implementato IDisposable?Questo è un po 'complicato:

  • se si possiede risorse, è necessario garantire che possano essere liberati da esplicita Dispose chiamata o da GC, ma non da entrambi. Quindi, hai bisogno di una bandiera che indica il fatto di smaltimento. Per una minore duplicazione del codice, il codice di smaltimento viene spostato in un metodo separato.

Esempio:

bool disposed; 
public void Dispose(){ 
    Dispose(true); 
    GC.SuppressFinalize(this); // tell GC not to call Finalizer() for this object 
} 

~MyObject(){ 
    Dispose(false); 
} 

void Dispose(bool manualDisposing){ 
    if(!disposed){ 
     disposed = true; 
     if(manualDisposing) 
      ... // call Dispose on all IDisposable fields 
     ... // dispose all native resources 
    } 
} 
  • se non siete in possesso di risorse, come nel caso di TimeMeasure di classe, senza bisogno di Finalizer, basta fare logica necessaria a Dispose.
2

Fondamentalmente IDisposable a un livello elevato, in combinazione con la parola chiave using ti dà il supporto sintattico per quello che si vede come un idioma Java comuni come questo:

Connection c = null; 
    try { 
     c = getConnection(); 
     .... 
    } finally { 
     if (c != null) { 
      c.close(); 
     } 
    } 

Se Java aveva un utilizzo di parole chiave e di un interfaccia IDisposable con un metodo close(), potrebbe assomigliare a questo:

//psudo-Java 
    using(Connection c = getConnection()) { 
     ..... 
    } 

con il metodo close essere implicitamente chiamato alla fine di quel blocco. Non c'è bisogno di provare/finalmente.

Detto questo, IDisposible ha un contratto abbastanza complesso e si occupa principalmente di liberare memoria non gestita. Devi lavorare duro con Java per avere memoria non gestita (fondamentalmente con i componenti JNI e Swing, hai il concetto), ma è molto più comune in .NET, quindi c'è un supporto linguistico per il concetto.

11

Con java 1.7 è disponibile la nuova dichiarazione try-with-resource.

try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
    return br.readLine(); 
} 

Gli oggetti utilizzati devono implementare l'interfaccia AutoCloseable. Non è esattamente la stessa di IDisposable, ma il close() viene chiamato automaticamente in infine. Questo dà l'opportunità di implementare un comportamento simile.

Il codice di cui sopra è lo stesso di

BufferedReader br = new BufferedReader(new FileReader(path)); 
try { 
    return br.readLine(); 
} finally { 
    if (br != null) br.close(); 
} 

Per saperne di più su questo in java tutorial. Il samplecode viene da lì.

+0

Questa dovrebbe essere la risposta accettata. Non solo spiega come funziona il concetto usa e getta, ma mostra come questo sia implementato su Java. Tutte le altre risposte si riferiscono solo al meccanismo C#. – JavierIEH

+0

AutoCloseable non AutoClosable – Sonny

0

L'interfaccia IDisposable viene utilizzata per liberare manualmente le risorse non gestite.