Dovrei utilizzare IDisposable qui, per gestire correttamente la memoria?

1

Sfondo

Ho un oggetto che rappresenta una procedura di test che devo eseguire su un prodotto. Questo oggetto può essere utilizzato più volte durante l'esecuzione, a seconda di quante volte l'utente decide di eseguire il test. Ecco dove inizia la sfida del design. Questo oggetto TestProcedure contiene molti membri che mantengono i loro valori per tutta la durata dell'oggetto.

Quando l'oggetto viene istanziato, i suoi membri hanno bisogno di avere valori iniziali specifici . Quindi, se l'operatore termina il test e decide di riavviarlo, questi membri non hanno più alcun significato. Detto questo ... se non resetto i membri prima di eseguire un altro test, i valori iniziali saranno errati e quindi invalideranno il test.

Invece di reimpostare ogni membro sul valore che dovrebbe essere, ecco cosa sto facendo invece ...

private TestProcedure myProcedure = null;
private CancellationTokenSource myTokenSource = new CancellationTokenSource();
private CancellationToken myToken = CancellationToken.None;

// creates and executes a test procedure
public void Run()
{
    // get a new token source
    this.myTokenSource = new CancellationTokenSource();

    // get a new token
    this.myToken = myTokenSource.Token;

    // instantiate a new procedure with the token
    myProcedure = new TestProcedure(myTokenSource);

    // do the work inside the procedure
    myProcedure.DoWork();
}

Quindi, quando vedo un problema è che quando l'utente va a creare un rieseguire il test ...% verrà chiamato% co_de, così a sua volta sto solo sovrascrivendo il vecchio oggetto con un nuova istanza . Sento che questo potrebbe non essere il modo corretto di fare le cose. Sento che sto gestendo male la memoria qui.

Domanda

Non è questa una di quelle situazioni in cui dovremmo usare un'istruzione Run e implementare using , oppure posso fare a meno di fare le cose come le ho adesso?

    
posta Snoop 02.05.2016 - 16:16
fonte

2 risposte

4

Se TestProcedure contiene esclusivamente oggetti gestiti (al contrario delle risorse come connessioni al database, oggetti GDI +, ecc.), non c'è nulla che devi fare. Basta creare una nuova istanza di TestProcedure all'inizio del test e lasciare che Garbage Collector gestisca la rimozione dell'oggetto al termine del test.

Se TestProcedure utilizza oggetti che dovrebbero essere rilasciati il prima possibile, come una connessione a un database, quindi:

  • O assicurati che la risorsa venga utilizzata all'interno di un'istruzione using () { } all'interno di TestProcedure stessa, in modo che venga eliminata immediatamente dopo averla terminata. Ad esempio, invece di mantenere un'istanza SqlConnection all'interno di TestProcedure , fornire entro TestProcedure i metodi che aprono una connessione quando viene chiamato e chiudila / disporla immediatamente prima di uscire.

  • Oppure imposta TestProcedure implementa IDisposable se l'approccio precedente richiede troppo codice (cosa che potrebbe accadere se si utilizza la stessa risorsa non gestita molto o se si utilizzano molte risorse diverse non gestite).

Parlando delle tue preoccupazioni riguardo ai valori che non riflettono la realtà, assicurati che le istanze siano locali al metodo Run , dal momento che sembra che tu non usi la variabile da nessun'altra parte. In altre parole, invece di:

private TestProcedure myProcedure = null;

public void Run()
{
    ...
    myProcedure = new TestProcedure(myTokenSource);
    myProcedure.DoWork();
}

fare:

public void Run()
{
    ...
    new TestProcedure(myTokenSource).DoWork();
}

Ogni chiamata a Run creerà una nuova istanza della classe TestProcedure ; se il metodo viene chiamato più volte, i valori della vecchia chiamata non "inquinano" il contesto di una nuova chiamata. Ogni istanza verrà mantenuta non appena necessario e quindi rimossa da Garbage Collector.

    
risposta data 02.05.2016 - 16:47
fonte
2

La domanda principale sull'opportunità o meno di implementare IDisposable è se si utilizzano risorse non modificate.

Dalla documentazione IDisposable

The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.

Se nulla di quello che usi è fuori dal framework .net (e chiama dispose / wrap in usando le istruzioni quando necessario) allora la garbage collection si occuperà di ripulire ogni cosa e non dovrai preoccuparti.

Tendo ad implementare IDisposible nelle seguenti circostanze, nonché quando si tratta di risorse non gestite:

Ogni volta che una risorsa di livello classe implementa IDisposable (IE: una classe che accede a un contesto di Entity Framework) che voglio eliminare correttamente.

Nelle librerie in cui la maggior parte delle altre classi lo ha implementato per i due motivi sopra esposti e voglio mantenere un'interfaccia coerente. Questo è puramente stilistico e non è necessario, ma quando leggo il codice se tengo sempre il codice da quella libreria in un'istruzione using rende le cose più facili da leggere.

    
risposta data 02.05.2016 - 16:50
fonte

Leggi altre domande sui tag