Sono quasi certo che la risposta sia SI. Se utilizzo un blocco Prova finalmente ma non utilizzo un blocco Catch, tutte le eccezioni VERRANNO gonfiate. Corretta?
Qualche idea sulla pratica in generale?
Seth
Sono quasi certo che la risposta sia SI. Se utilizzo un blocco Prova finalmente ma non utilizzo un blocco Catch, tutte le eccezioni VERRANNO gonfiate. Corretta?
Qualche idea sulla pratica in generale?
Seth
Risposte:
Sì, lo farà assolutamente. Supponendo che il tuo finallyblocco non generi un'eccezione, ovviamente, nel qual caso ciò "sostituirà" effettivamente quello che è stato originariamente lanciato.
Qualche idea sulla pratica in generale?
Sì. Stai attento . Quando il tuo blocco finalmente è in esecuzione, è del tutto possibile che sia in esecuzione perché è stata lanciata un'eccezione imprevista non gestita . Ciò significa che qualcosa è rotto e potrebbe accadere qualcosa di completamente inaspettato .
In quella situazione è probabilmente il caso che non dovresti affatto eseguire codice in blocchi alla fine. Il codice nel blocco finalmente potrebbe essere costruito per presumere che i sottosistemi da cui dipende siano integri, quando in realtà potrebbero essere profondamente danneggiati. Il codice nel blocco finalmente potrebbe peggiorare le cose.
Ad esempio, vedo spesso questo genere di cose:
DisableAccessToTheResource();
try
{
DoSomethingToTheResource();
}
finally
{
EnableAccessToTheResource();
}
L'autore di questo codice sta pensando "Sto apportando una mutazione temporanea allo stato del mondo; ho bisogno di riportare lo stato a quello che era prima di essere chiamato". Ma pensiamo a tutti i modi in cui ciò potrebbe andare storto.
Innanzitutto, l'accesso alla risorsa potrebbe già essere disabilitato dal chiamante; in tal caso, questo codice lo riattiva, possibilmente prematuramente.
Secondo, se DoSomethingToTheResource genera un'eccezione, è la cosa giusta da fare per abilitare l'accesso alla risorsa ??? Il codice che gestisce la risorsa è inaspettatamente interrotto . Questo codice dice, in effetti, "se il codice di gestione è danneggiato, assicurati che un altro codice possa chiamare quel codice non funzionante il prima possibile, in modo che possa anche fallire in modo orribile ". Sembra una cattiva idea.
Terzo, se DoSomethingToTheResource genera un'eccezione, come facciamo a sapere che anche EnableAccessToTheResource non genererà un'eccezione? Qualunque sia la gravità dell'uso della risorsa potrebbe anche influenzare il codice di pulizia, nel qual caso l'eccezione originale andrà persa e il problema sarà più difficile da diagnosticare.
Tendo a scrivere codice come questo senza utilizzare i blocchi di prova finale:
bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
EnableAccessToTheResource();
Ora lo stato non è mutato a meno che non sia necessario. Ora lo stato del chiamante non è incasinato. E ora, se DoSomethingToTheResource fallisce, non riabilitiamo l'accesso. Partiamo dal presupposto che qualcosa sia profondamente rotto e non rischiamo di peggiorare la situazione cercando di mantenere il codice in esecuzione. Lascia che il chiamante si occupi del problema, se può.
Allora, quando è una buona idea eseguire un blocco finale? Primo, quando è prevista l'eccezione. Ad esempio, potresti aspettarti che un tentativo di bloccare un file possa fallire, perché qualcun altro lo ha bloccato. In tal caso ha senso rilevare l'eccezione e segnalarla all'utente. In quel caso si riduce l'incertezza su ciò che è rotto; è improbabile che peggiorerai le cose pulendo.
In secondo luogo, quando la risorsa che stai ripulendo è una risorsa di sistema scarsa. Ad esempio, ha senso chiudere un handle di file in un blocco finalmente. (Un "utilizzo" è ovviamente solo un altro modo di scrivere un blocco di prova finale.) Il contenuto del file potrebbe essere danneggiato, ma non c'è niente che tu possa fare al riguardo ora. L'handle del file verrà chiuso alla fine, quindi potrebbe anche essere prima o poi.