It Lang Vb

Transcript

It Lang Vb
Visual Basic .NET – La Gestione degli Errori
di Federico BARBATI
Generalità
La gestione degli errori, è una parte fondamentale di un codice ben progettato. Fino ad oggi, gli errori nelle
applicazioni scritte in Visual Basic venivano gestite con le istruzioni ON ERROR GOTO… e ON ERROR
RESUME NEXT. Visual Basic .Net supporta le “vecchie” istruzioni tuttavia, questa gestione è considerata una
cattiva abitudine dato che è stata introdotta una nuova gestione strutturata utilizzando l’istruzione:
Try… Catch … Finally.
Il problema legato alla gestione degli errori tradizionale è che non esiste una metodologia comune. Ci sono per
esempio delle DLL che notificano un errore con uno 0 altre invece con un 1. Alcuni linguaggi di
programmazione hanno dei propri meccanismi COM altri come C++, adottano il meccanismo delle eccezioni.
Per ottenere l’interoperabilità tra i vari linguaggi, con il Framework .Net è stato introdotto un metodo unico per
la gestione degli errori comune a tutti i linguaggi .Net: la generazione/intercettazione degli errori basato sulle
eccezioni.
Quando durante l’esecuzione di un’applicazione si verifica una condizione inaspettata (e quindi non gestita
dallo sviluppatore), il codice solleva un’eccezione che altro codice dovrà intercettare.
L’eccezione può essere intercettata dal codice della stessa procedura che ha sollevato l’errore. Se questo non
accade, l’eccezione viene sollevata al chiamante e se quest’ultimo non l’intercetta, al chiamante del chiamante.
Per cui l’eccezione risale fino a quando non viene intercettata da qualche procedura (logica top-down).
Se non esiste nella nostra applicazione una procedura in grado di intercettare l’eccezione, verrà visualizzata in
automatico una finestra di questo tipo:
Questo vuol dire che con VB.Net, non ci sarà un’uscita brusca dal programma (con una probabile perdita di
dati) come accade con VB6, ma si avrà la possibilità di ignorare l’errore e quindi continuare con l’esecuzione
dell’applicazione.
In effetti, quando viene sollevata un’eccezione, viene passata alla procedura che ha provocato l’errore, un
oggetto Exception, il quale metterà a disposizione i suoi metodi e le sue proprietà .
Tra le proprietà più utilizzate troviamo:
• Message: Restituisce la descrizione dell’eccezione come Err.Description in VB6;
• Source: Indica dove si verifica l’eccezione come Err.Source in VB6;
• StackTrace: Partendo dal metodo che ha restituito l’eccezione, restituisce anche tutti i metodi
chiamanti;
• TargetSite: Restituisce nome e firma del metodo che ha sollevato l’eccezione.
Il metodo ToString restituisce la descrizione dell’eccezione come verrebbe mostrata all’utente finale nel caso
in cui non ci fosse una gestione da parte del codice. Oltre a mostrare il contenuto della proprietà Message,
restituisce anche il nome del modulo sorgente.
L’oggetto Exception, è definito all’interno del Framework .Net ed il suo namespace è: System.Exception,
tuttavia le applicazioni sollevano gli errori ereditando dai namespace:
•
•
System.SystemException (che eredita direttamente da System.Exception)
System.ApplicationException.
In definitiva, tutte le eccezioni definite nel Framework .Net ereditano da System.Exception mentre tutte le
eccezioni personalizzate dall’utente all’interno di un’applicazione, ereditano da System.ApplicationException.
Per esempio il namespace System.IO può sollevare un’eccezione System.DirectoryNotFoundException
(directory non trovata) o System.FileNotFoundException (File non trovato), mentre una divisione può
sollevare l’eccezione System.DivideByZeroException (divisione per 0) che a loro volta ereditano direttamente
da System.Exception (l’elenco completo è contenuto nella documentazione originale dell’SDK installata con
Visual Studio .Net).
L’Istruzione Try…Catch…Finally
Quando si esegue un codice che potrebbe sollevare un’eccezione, è bene inserirlo in un costrutto Try..End Try.
Ad esempio:
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 2
Valore2 = 0
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As Exception
MessageBox.Show(provaEx.Message)
End Try
Da notare che le tre variabili verranno dichiarate tutte Integer mentre in VB6 le prime due erano Variant e solo
la terza (Valore2) era Integer. Inoltre “\” effettua una divisione tra interi mentre “/” effettua una divisione in
virgola mobile,
Se il codice tra Try e Catch provoca un errore, Visual Basic, passerà il controllo al blocco Catch, inversamente
ignorerà tutto quello dopo il Catch.
In questo caso verrà restituito alla procedura, un oggetto provaEx di tipo System.Exception e mediante un
MessageBox verrà visualizzata la proprietà provaEx.Message la quale restituisce la descrizione dell’eccezione.
In quest’ultimo caso, non abbiamo sfruttato la flessibilità dell’istruzione dato che il filtro del blocco Catch è
impostato sul generico tipo Exception.
Per questo motivo, per ottenere un controllo più selettivo, useremo più blocchi Catch ognuno dei quali verifica
un diverso tipo Exception.
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 2
Valore2 = 0
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As DivideByZeroException
MessageBox.Show("Divisione per 0!", "Eccezione:")
Catch provaEx As OverflowException
MessageBox.Show("Overflow!", "Eccezione:")
Catch provaEx As Exception
MessageBox.Show("Altra!", "Eccezione:")
End Try
Visual Basic confronta l’eccezione sollevata con le espressioni contenute nelle clausole Catch nell’ordine in cui
sono scritte.
In questo caso siamo in grado di intercettare una errore di divisione per 0, oppure un overflow e di conseguenza
inserire il codice per la gestione più adatto. Ad esempio, quando si verifica un’eccezione
DivideByZeroException, potremmo richiedere all’utente un nuovo valore per la variabile Valore2. Tuttavia è
bene inserire alla fine un blocco Catch generico in grado di intercettare tutti i tipi di eccezione.
E’ possibile uscire da un Try…End Try invocando l’istruzione Exit Try che può apparire anche nei blocchi
Catch.
Il runtime del .Net definisce automaticamente alcune eccezioni che si verificano in condizioni non dipendenti
dal programma ma dal sistema (StackOverflowException, OutOfMemoryException,).
La Parola Chiave WHEN
La parola chiave When (non gestita in C#) permette di specificare un’ulteriore condizione da soddisfare al filtro
impostato in un blocco Catch. In questo esempio, utilizzeremo più blocchi Catch con filtro identico ma con
condizione When diversa:
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 10
Valore2 = 0
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As DivideByZeroException When Valore1 < 10
MessageBox.Show("Divisione per 0 per valore1 < 10!", "Eccezione:")
Catch provaEx As DivideByZeroException When Valore1 >= 10
MessageBox.Show("Divisione per 0 per valore1 >= 10!", "Eccezione:")
Catch provaEx As OverflowException
MessageBox.Show("Overflow!", "Eccezione:")
Catch provaEx As Exception
MessageBox.Show("Altra!", "Eccezione:")
End Try
Con la gestione dell’esempio, verrà eseguito il secondo blocco Catch dato che Valore1 = 10.
E’ comunque da tenere in considerazione che si può arrivare allo stesso risultato usando il costrutto
If..Then..Else perdendo comunque leggibilità e organizzazione.
La parola chiave Finally
Quando viene sollevato un errore, spesso si ha la necessità di utilizzare un codice di cleanup ad esempio
chiudere un file o una connessione ad un database.
La parola chiave Finally è utilizzata in questi casi. Tutto il codice inserito tra Finally ed End Try verrà eseguito
indipendentemente dal fatto che sia stata sollevata un’eccezione o meno.
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 10
Valore2 = 0
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As DivideByZeroException When Valore1 < 10
MessageBox.Show("Divisione per 0 per valore1 < 10!", "Eccezione:")
Catch provaEx As DivideByZeroException When Valore1 >= 10
MessageBox.Show("Divisione per 0 per valore1 >= 10!", "Eccezione:")
Catch provaEx As OverflowException
MessageBox.Show("Overflow!", "Eccezione:")
Catch provaEx As Exception
MessageBox.Show("Altra!", "Eccezione:")
Finally
MessageBox.Show("Il valore1=" & Str(Valore1) & " ed il Valore2=" &
Str(Valore2))
End Try
Con questo codice apparirà una MessageBox che visualizza i valori delle variabili Valore1 e Valore2
indipendentemente dal fatto che venga sollevata un’eccezione. Il codice dopo Finally verrà eseguito perfino se
si utilizza un Exit Try.
Nel menu Debug di Visual Studio .Net, ciccando su Eccezioni, verrà visualizzata la finestra di dialogo
Eccezioni. Questa finestra di dialogo, mostra tutti i tipi di eccezioni gestite dal runtime del .Net raggruppate per
Namespace per cui può essere utile per avere una visione più ampia delle vari tipi.
Selezionando un nodo oppure una singola eccezione, si può decidere, (nel caso in cui l’applicazione intercetti
l’eccezione selezionata) se continuare e ignorare l’errore oppure passare il controllo al debugger .
E’ possibile infine sollevare un’eccezione utilizzando Throw (che corrisponde a Err.Raise in VB6). Ad
esempio, potrei decidere di sollevare un’eccezione se la variabile Valore2 è minore o uguale a zero:
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 10
Valore2 = 0
If Valore2 <= 0 Then
Throw New DivideByZeroException("Valore2 deve essere > di 0")
End If
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As Exception
MessageBox.Show(provaEx.Message)
End Try
Quando il valore della variabile Valore2 = 0, il codice solleva un’eccezione DivideByZeroException e tra
parentesi personalizza il messaggio che verrà restituito.
E’ possibile utilizzare Throw anche all’interno di un blocco Catch per notificare al chiamante l’eccezione:
Dim Divisione, Valore1, Valore2 As Integer
Try
Valore1 = 10
Valore2 = 0
Divisione = Valore1 \ Valore2
MessageBox.Show(Divisione)
Catch provaEx As Exception
MessageBox.Show("Altra!", "Eccezione:")
Throw
End Try
Nell’esempio, se una procedura chiama la funzione Divisione, alla procedura chiamante, verrà restituita
l’eccezione solo perchè gli viene notificata tramite Throw.
Concludo consigliando vivamente di utilizzare questa novità di VB.Net a scapito di On Error... perchè
l’esecuzione sarà più veloce e consente l’interoperabilità con altri linguaggi (C#) che non supportano la vecchia
gestione VB6.
N.B. Per dubbi e chiarimenti scrivere a [email protected]