2010-08-26 6 views
10

Non ho bisogno di una lezione per passare da metodi ricorsivi a non ricorsivi, voglio solo sapere perché non possiamo affrontare questo tipo di eccezione. Indipendentemente da ciò, sto usando funzioni ricorsive su liste molto grandi.C# - Come si gestisce/cattura StackOverFlowExceptions?

Ho scritto il codice per tentare di catturare StackOverFlowExceptions:

try { recursiveFxn(100000); } 
catch(Exception){}
private void recursiveFxn(int countdown) 
{ 
if (countdown > 0) 
    recursiveFxn(countdown - 1); 
else 
    throw new Exception("lol. Forced exception."); 
}

Ma ancora ottengo programma va in crash (sia in NUnit e una pagina web sto correndo). Perché non viene rilevata l'eccezione?

+0

Sono piuttosto sorpreso che questa eccezione esista ... al di fuori del codice gestito, non sono convinto che sia possibile recuperare da questo errore in generale. –

+0

@RobertKarl: Vorrei che esistesse un mezzo tramite il quale il codice potesse verificare esplicitamente lo stack per una certa quantità di spazio, con un'eccezione generata se lo spazio non era disponibile. Se un tale metodo ha gettato l'eccezione prima che lo stack trabocchi, e se la quantità di spazio richiesta era almeno uguale alla somma del massimo circa dello stack che verrà assegnato tra i test, più l'importo richiesto per il codice di ripristino, tali eccezioni potrebbero essere recuperabile al 100%. Così com'è, non conosco il modo di scrivere codice ricorsivo sicuro che non limiti artificialmente la profondità delle strutture che può gestire. – supercat

risposta

16

Poiché .NET Framework 2.0, StackOverflowException non può essere rilevato. Questo perché è considerato una cattiva pratica. Citando il MSDN documentation:

A partire con il .NET Framework versione 2.0, un oggetto StackOverflowException non può essere catturato da un blocco try-catch e il processo corrispondente è terminato per impostazione predefinita. Di conseguenza, agli utenti di si consiglia di scrivere il codice per rilevare e impedire un sovraccarico dello stack . Ad esempio, se l'applicazione dipende dalla ricorsione, utilizzare un contatore o una condizione di stato su terminare il ciclo ricorsivo.

Ora, l'unico modo per prendere un StackOverflowException è quando è stato gettato dal codice utente, come spiegato in un blog by Jared Parsons. A parte questo, con hosting the CLR, puoi gestire (ma non prendere) uno StackOverflowException e trovare un modo per far continuare l'esecuzione del tuo programma.

noti che perché lo stack viene svolto quando si verifica un'eccezione, in pre-2,0 versioni Net stack sarebbe in realtà essere molto più breve quando il StackOverflowException viene gestita, rendendo possibile farlo senza generare un'altra StackOverflowException.

+0

Ottima risposta, grazie. – user420667

-1

Non è possibile rilevare un'eccezione di overflow dello stack perché, quando accade, uccide il thread dead. Prova ... catch ... viene eseguita dallo stesso thread in modo che non funzioni. Potrebbero esserci alcune API di livello inferiore che potresti P/Invoke e avere un altro thread che la cattura. Potrebbero esserci anche API di livello inferiore per modificare le dimensioni massime dello stack, ma non vedo nulla in .NET Framework per aiutare in questo modo, quindi di nuovo avresti bisogno di P/Invoke qualcosa.

+0

-1 perché come noto sopra, le eccezioni di overflow dello stack potrebbero essere rilevate nelle precedenti versioni di .Net, quindi la tua risposta che "non funzionerà perché è sullo stesso thread" è sbagliata. – Virtlink

+0

@Virtlink: Se ricordo correttamente, in .net 1.0, se provavo a catturare 'StackOverflowException', sarebbe" di solito "funzionante.C'è stato un notevole sovraccarico, tuttavia, nel consentire che tali eccezioni "di solito" vengano catturate prima che il contesto del thread fosse danneggiato irreparabilmente, e nonostante tale sovraccarico la funzionalità non fosse sufficientemente affidabile per essere utile. In .net 2.0, Microsoft ha deciso che era meglio richiedere che i programmatori usassero altri metodi di recupero da tali condizioni, piuttosto che sostenere l'overhead in modo che potessero provare a utilizzare un approccio di ripristino che potrebbe non funzionare comunque. – supercat