Sarebbe un cattivo progetto utilizzare IDisposable su una classe che gestisce gli aggiornamenti in batch?

6

Voglio una classe che avrà un singolo metodo sulla sua interfaccia per aggiungere aggiornamenti. Questi aggiornamenti verranno archiviati in una variabile interna della classe fino a quando non verrà raggiunta una dimensione di batch specificata. A quel punto verranno inviati tutti gli aggiornamenti e l'elenco degli aggiornamenti sarà cancellato.

Quando il mio programma sta uscendo, e ci sono ancora degli aggiornamenti in attesa di essere inviati dalla mia classe, potrei fare un altro metodo sull'interfaccia su "SubmitRemaining". Oppure potrei implementare l'idisposabilità e non richiedere ai consumatori di questa classe di preoccuparsi dei dettagli di implementazione. Questo sarebbe un uso valido di IDisposable, o c'è un altro modo in cui posso farlo?

    
posta Zach 19.03.2017 - 23:32
fonte

3 risposte

6

Lo scopo "ufficiale" di IDisposable è di ripulire le risorse non gestite. Le risorse non gestite sono cose come le classi COM che non possono essere raccolte da garbage. runtime.

Tuttavia, IDisposable (cioè il metodo Dispose() ) è stato utilizzato anche per:

  1. Chiudi uno stream gestito,
  2. Esegui una richiamata automatica,
  3. Scrivi un tag HTML finale,
  4. Crea un ambito che racchiude.

L'unica preoccupazione che ho con alcuni di questi usi è che non trasmettono il significato semantico corretto. Il programmatore che viene dopo di te che deve leggere il tuo codice supporrà che IDisposable comprenda qualcosa che richiede eliminazione, o almeno una sorta di pulizia semanticamente significativa. Se crei effetti collaterali inaspettati con esso, causerai confusione.

Vorrei quindi documentare in dettaglio come l'interfaccia IDisposable sia implementata in modo specifico nella definizione della classe (ad esempio i commenti XML), in modo che tutti siano chiari su come funziona esattamente nel tuo contesto specifico.

Ulteriori letture
Uso improprio delle dichiarazioni
Esempio di creazione dell'ambito con l'istruzione using
Esiste un'alternativa migliore dell'abuso il modello IDisposable?
L'uso illecito di IDisposable può trarre beneficio dall'uso di dichiarazioni considerate dannose?
È abusivo usare IDisposable e "using" come mezzo per ottenere "scope scope"?

    
risposta data 20.03.2017 - 02:41
fonte
2

A prima vista, IDisposable è adatto per i processi batch.

Se stai facendo un singolo processo atomico, sai all'inizio che puoi chiudere le tue risorse quando hai finito.

Tuttavia, con una procedura batch è possibile mantenere le risorse aperte più a lungo, mentre si elaborano più cose. In questo caso il tuo codice di elaborazione non sa quando chiudere le sue risorse ed è necessario chiamare Dispose in modo esplicito.

Tuttavia! Il resto della tua domanda implica che questo NON è ciò che vuoi utilizzare per IDisposable! Sembra che tu voglia avere una chiamata automatica per terminare l'elaborazione del batch prima che il programma termini.

Questa non è una buona idea. Ci sono molti casi in cui questo non funzionerà.

Inoltre, affidandosi a Dispose () o alla chiusura di un'istruzione using per eseguire altre funzionalità, sebbene sia stato utilizzato per fare trucchi "intelligenti" nel framework .net, è solo per chiedere problemi che non ti servono.

Sembra che tu stia meglio con alcune attività o eventi asincroni per dirti quando il batch è completo

Un metodo che ho usato in una situazione simile è quello di inviare il batch quando viene raggiunto il conteggio delle soglie OPPURE un timer scade. Questo limita la tua esposizione a situazioni in cui hai 9/10 articoli in attesa di essere inviati per ore

    
risposta data 20.03.2017 - 06:48
fonte
0

Dispose sembra uno schema piacevole perché è garantito che venga chiamato in determinati costrutti, ad es.

using (var myCache = cacheFactory.GetCache())
{
    mycache.WriteData();
}

... finirà sempre per chiamare Dispose.

Ma ... cosa succede se qualcosa va storto con il commit? Per esempio. il tuo disco è pieno o il tuo database è inattivo? Quindi devi fare questo:

try
{
    using (var myCache = cacheFactory.GetCache())
    {
        mycache.WriteData();
    }
}
catch(SomeException ex)
{
    //What do I do now?  Is my object disposed or not?
}

Ecco perché una delle regole per Dispose è

Don’t throw exceptions in Dispose. Nothing should go wrong with your object calling Dispose. Mainly for reasons stated above.

Se l'atto di commettere la cache potrebbe sollevare un'eccezione, non utilizzare Dispose. Crea un nuovo metodo chiamato Flush() o qualcosa di simile. Quindi il tuo sviluppatore ha più controllo su di esso e può fare qualcosa del genere:

try
{
    myCache.WriteData();
    myCache.Flush();
}
catch(SomeException ex)
{
    //Do something about it
}

Se lo desideri, puoi anche implementare Dispose come back-stop, in questo modo:

void Dispose()
{
    try
    {
        this.Flush();
    }
    catch
    {
        //Swallow exception
    } 
}

... che ti dà il meglio di entrambi i mondi. Adesso puoi scrivere:

using (var myCache = cacheFactory.GetCache())
{
    try
    {
        mycache.WriteData();
        myCache.Flush();
    }
    catch(SomeException ex)
    {
        //Deal with it
    }
}

... ma non sei del tutto sicuro se qualcuno dimentica di chiamare Flush .

    
risposta data 20.03.2017 - 20:13
fonte

Leggi altre domande sui tag