Try...Catch...Finally Istruzione (Visual Basic)

Fornisce un metodo per gestire alcuni o tutti i potenziali errori che potrebbero verificarsi in un determinato blocco di codice senza interrompere l’esecuzione del codice.

Sintassi

Try
    [ tryStatements ]
    [ Exit Try ]
[ Catch [ exception [ As type ] ] [ When expression ]
    [ catchStatements ]
    [ Exit Try ] ]
[ Catch ... ]
[ Finally
    [ finallyStatements ] ]
End Try

Parti

Termine Definizione
tryStatements Facoltativo. Istruzioni nelle quali potrebbe verificarsi un errore. Può essere un'istruzione composta.
Catch Facoltativo. Diversi blocchi Catch consentiti. Se dovesse verificarsi un'eccezione durante l'elaborazione del blocco Try, ogni istruzione Catch verrà esaminata in ordine testuale per determinare se gestisca l'eccezione, con exception come rappresentazione dell'eccezione generata.
exception Facoltativo. Qualsiasi nome di variabile. Il valore iniziale di exception corrisponde al valore dell'errore generato. Usato con Catch per specificare l'errore rilevato. Se omesso, l'istruzione Catch intercetta qualsiasi eccezione.
type Facoltativo. Specifica il tipo di filtro di classe. Se il valore di exception è del tipo specificato da type o di un tipo derivato, l'identificatore viene associato all'oggetto eccezione.
When Facoltativo. Un'istruzione Catch con una clausola When rileva le eccezioni solo quando expression restituisce True. Una clausola When viene applicata solo dopo aver controllato il tipo di eccezione, e expression potrebbe fare riferimento all'identificatore che rappresenta l'eccezione.
expression Facoltativo. Deve essere implicitamente convertibile a Boolean. Qualsiasi espressione che descrive un filtro generico. Generalmente usato per filtrare in base al numero di errore. Usato con la parola chiave When per specificare le circostanze in cui l'errore è rilevato.
catchStatements Facoltativo. Istruzioni per la gestione di errori che si verificano nel blocco associato Try. Può essere un'istruzione composta.
Exit Try Facoltativo. Parola chiave che evade la struttura Try...Catch...Finally. L'esecuzione riprende con il codice immediatamente successivo all'istruzione End Try. L'istruzione Finally verrà comunque eseguita. Non consentito nei blocchi Finally.
Finally Facoltativo. Un blocco Finally viene sempre eseguito quando l'esecuzione lascia qualsiasi parte dell'istruzione Try...Catch.
finallyStatements Facoltativo. Istruzione/i eseguita/e dopo che l’elaborazione di tutti gli altri errori è completata.
End Try Termina la struttura Try...Catch...Finally.

Osservazioni:

Se si prevede che possa verificarsi una particolare eccezione in una particolare sezione di codice, inserire il codice in un blocco Try e usare un blocco Catch per mantenere il controllo e gestire la potenziale eccezione.

Un'istruzione Try…Catch è costituita da un blocco Try seguito da una o più clausole Catch, che specificano i gestori per varie eccezioni. Quando viene generata un'eccezione in un blocco Try, Visual Basic cerca l'istruzione Catch che gestisce l'eccezione. Se non viene trovata un'istruzione corrispondente Catch, Visual Basic esamina il metodo che ha chiamato il metodo corrente, e così via, sullo stack di chiamate. Se non viene trovato alcun blocco Catch, Visual Basic mostra un messaggio di eccezione non gestita per l'utente e interrompe l'esecuzione del programma.

È possibile usare più di un'istruzione Catch in un'istruzione Try…Catch. In questo caso, l'ordine delle clausole Catch è rilevante, poiché le clausole vengono esaminate in ordine. Catch le eccezioni più specifiche prima di quelle meno specifiche.

Le seguenti condizioni dell'istruzione Catch sono le meno specifiche e intercettano tutte le eccezioni derivanti dalla classe Exception. È consigliabile usare generalmente una di queste varianti come ultimo blocco Catch nella struttura Try...Catch...Finally, dopo aver intercettato tutte le eccezioni specifiche previste. Il flusso di controllo non è mai in grado di raggiungere un blocco Catch che segue una di queste varianti.

  • type è Exception, ad esempio: Catch ex As Exception

  • L'istruzione non ha alcuna variabile exception, ad esempio: Catch

Quando un'istruzione Try…Catch…Finally è annidata in un altro blocco Try, Visual Basic esamina innanzitutto ogni istruzione Catch nel blocco Try più interno. Se non viene trovata alcuna istruzione Catch corrispondente, la ricerca procede alle istruzioni Catch del blocco esterno Try…Catch…Finally.

Le variabili locali di un blocco Try non sono disponibili in un blocco Catch, poiché si tratta di due blocchi separati. Se si desidera usare una variabile in più blocchi, dichiarare la variabile all'esterno della struttura Try...Catch...Finally.

Suggerimento

L'istruzione Try…Catch…Finally è disponibile come frammento di codice IntelliSense. In Gestione frammenti di codice, espandere Criteri di codice - Se, Per ogni, TryCatch, Proprietà, e così via, quindi Gestione degli errori (Eccezioni). Per altre informazioni, vedere Code Snippets.

Blocco Finally

Se una o più istruzioni devono essere eseguite prima di uscire dalla struttura Try, usare un blocco Finally. Il controllo passa al blocco Finally subito prima che passi dall’esterno della struttura Try…Catch. Questo vale anche nel caso in cui dovesse verificarsi un'eccezione in qualsiasi punto all’interno della struttura Try.

Un blocco Finally è utile per l'esecuzione di qualsiasi codice che debba essere necessariamente eseguito anche in presenza di un'eccezione. Il controllo viene passato al blocco Finally indipendentemente dalla modalità di uscita del blocco Try...Catch.

Il codice in un blocco Finally viene eseguito anche se il codice rileva un'istruzione Return in un blocco Try o Catch. Il controllo non passa da un blocco Try o Catch al Finally corrispondente nei seguenti casi:

Il trasferimento esplicito dell'esecuzione a un blocco Finally non è valido. Il trasferimento dell'esecuzione da un Finally blocco non è valido, salvo tramite un'eccezione.

Se un'istruzione Try non contiene almeno un blocco Catch, deve necessariamente contenere un blocco Finally.

Suggerimento

Se non si necessita di intercettare eccezioni specifiche, l'istruzione Using si comporta come un blocco Try…Finally e garantisce l'eliminazione delle risorse, indipendentemente dalla modalità di uscita dal blocco. Questo vale anche per un'eccezione non gestita. Per altre informazioni, vedere Istruzione using.

Argomento eccezione

L'argomento di Catchbloccoexception è un'istanza della classe Exception o di una classe derivante dalla classe Exception. L'istanza della classe Exception corrisponde all'errore che si è verificato nel blocco Try.

Le proprietà dell'oggetto Exception consentono di identificare la causa e la posizione di un'eccezione. Ad esempio, la proprietà StackTrace elenca i metodi chiamati che hanno condotto all'eccezione, consentendo di individuare dove si è verificato l'errore nel codice. Message restituisce un messaggio che descrive l’eccezione l'eccezione. HelpLink restituisce un collegamento a un file Guida pertinente. InnerException restituisce l'oggetto Exception che ha causato la corrente eccezione, o restituisce Nothing se non è presente alcun Exception originale.

Considerazioni sull'uso di un'istruzione Try…Catch

Usare un'istruzione Try…Catch solo per segnalare l'occorrenza di eventi di programma insoliti o imprevisti. Ciò dipende da diversi fattori, sono riportati di seguito:

  • Eseguire Catch sulle eccezioni in fase di esecuzione crea un sovraccarico aggiuntivo ed è probabilmente un’operazione più lenta rispetto al controllo preliminare per la prevenzione di eccezioni.

  • Se un blocco Catch non viene gestito correttamente, l'eccezione potrebbe non essere correttamente segnalata agli utenti.

  • La gestione delle eccezioni rende un programma più complesso.

Non è sempre necessaria un'istruzione Try…Catch per verificare la presenza di una potenziale condizione. Nel seguente esempio viene verificato se un file è esistente prima di tentare di aprirlo. In questo modo, si riduce la necessità di intercettare un'eccezione generata dal metodo OpenText.

Private Sub TextFileExample(ByVal filePath As String)

    ' Verify that the file exists.
    If System.IO.File.Exists(filePath) = False Then
        Console.Write("File Not Found: " & filePath)
    Else
        ' Open the text file and display its contents.
        Dim sr As System.IO.StreamReader =
            System.IO.File.OpenText(filePath)

        Console.Write(sr.ReadToEnd)

        sr.Close()
    End If
End Sub

Accertarsi che il codice in blocchi Catch possa segnalare correttamente le eccezioni agli utenti, che sia tramite registrazione thread-safe o appositi messaggi. In caso contrario, le eccezioni potrebbero rimanere ignote.

Metodi asincroni

Se si contrassegna un metodo con il modificatore Async, è possibile usare l'operatore Await nel metodo. Un'istruzione con l'operatore Await sospende l'esecuzione del metodo fino al completamento dell'attività attesa. L'attività rappresenta il lavoro attualmente in fase di esecuzione. Al termine dell'attività associata all'operatore Await, l'esecuzione riprende nello stesso metodo. Per ulteriori informazioni, consultare Flusso di controllo in programmi asincroni.

Un'attività restituita da un metodo asincrono potrebbe terminare in uno stato di errore, indicando che è stata completata a causa di un'eccezione non gestita. Un'attività potrebbe anche terminare in uno stato di annullamento, comportando un'eccezione OperationCanceledException generata dall'espressione await. Per intercettare entrambi i tipi di eccezione, inserire l'espressione Await associata all'attività in un blocco Try e intercettare l'eccezione nel blocco Catch. Un esempio è fornito più avanti in questo argomento.

Un'attività potrebbe trovarsi in stato di errore perché più eccezioni sono responsabili dell'errore. Ad esempio, l'attività può essere il risultato di una chiamata a Task.WhenAll. Quando si attende tale attività, solo una delle eccezioni viene intercettata, ma non è possibile prevedere quale. Un esempio è fornito più avanti in questo argomento.

Un'espressione Await non può trovarsi all'interno di un blocco Catch o di un blocco Finally.

Iteratori

Una funzione iteratore o funzione di accesso Get esegue un'iterazione personalizzata su una raccolta. Un iteratore usa un'istruzione yield return per restituire ogni elemento della raccolta, uno alla volta. Per chiamare una funzione iteratore, usare l’Istruzione For Each... Next.

Un'istruzione Yield può trovarsi all'interno di un blocco Try. Un blocco Try contenente un'istruzione Yield può avere blocchi Catch e un blocco Finally. Per un esempio, vedere TryBlocchi.

Un'istruzione Yield non può trovarsi all'interno di un blocco Catch o di un blocco Finally.

Se il corpo For Each (all'esterno della funzione iteratore) genera un'eccezione, non viene eseguito un blocco Catch ma bensì un blocco Finally nella funzione iteratore. Un blocco Catch all'interno di una funzione iteratore rileva solo le eccezioni che si verificano all'interno di essa.

Situazioni di attendibilità parziale

In situazioni di attendibilità parziale (ad esempio, un'applicazione ospitata in una condivisione di rete), Try...Catch...Finally non rileva eccezioni di sicurezza che si verificano prima che venga richiamato il metodo che contiene la chiamata. L’esempio seguente, quando inserito in una condivisione server ed eseguito da questa posizione, genera l'errore "System.Security.SecurityException: Request Failed.” Per ulteriori informazioni sulle eccezioni di sicurezza, consultare la classe SecurityException.

Try
    Process.Start("http://www.microsoft.com")
Catch ex As Exception
    Console.WriteLine("Can't load Web page" & vbCrLf & ex.Message)
End Try

In una situazione di attendibilità parziale, è necessario inserire l'istruzione Process.Start in un Sub distinto. La chiamata iniziale a Sub avrà esito negativo. Questo permette a Try...Catch di intercettarlo prima che il Sub contenente Process.Start sia avviato e che l'eccezione di sicurezza sia generata.

Esempi

Struttura di Try...Catch...Finally

Il seguente esempio illustra la struttura dell’istruzione Try...Catch...Finally.

Public Sub TryExample()
    ' Declare variables.
    Dim x As Integer = 5
    Dim y As Integer = 0

    ' Set up structured error handling.
    Try
        ' Cause a "Divide by Zero" exception.
        x = x \ y

        ' This statement does not execute because program
        ' control passes to the Catch block when the
        ' exception occurs.
        Console.WriteLine("end of Try block")
    Catch ex As Exception
        ' Show the exception's message.
        Console.WriteLine(ex.Message)

        ' Show the stack trace, which is a list of methods
        ' that are currently executing.
        Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace)
    Finally
        ' This line executes whether or not the exception occurs.
        Console.WriteLine("in Finally block")
    End Try
End Sub

Eccezione in un metodo chiamato da un blocco Try

Nel seguente esempio, il metodo CreateException genera un'eccezione NullReferenceException. Il codice che genera l'eccezione non si trova in un blocco Try. Pertanto, il metodo CreateException non gestisce l'eccezione. Il metodo RunSample gestisce l'eccezione poiché la chiamata al metodo CreateException si trova in un blocco Try.

L'esempio include istruzioni Catch per vari tipi di eccezioni, ordinate dalla più specifica alla più generale.

Public Sub RunSample()
    Try
        CreateException()
    Catch ex As System.IO.IOException
        ' Code that reacts to IOException.
    Catch ex As NullReferenceException
        Console.WriteLine("NullReferenceException: " & ex.Message)
        Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace)
    Catch ex As Exception
        ' Code that reacts to any other exception.
    End Try
End Sub

Private Sub CreateException()
    ' This code throws a NullReferenceException.
    Dim obj = Nothing
    Dim prop = obj.Name

    ' This code also throws a NullReferenceException.
    'Throw New NullReferenceException("Something happened.")
End Sub

L’istruzione Catch When

L’esempio seguente illustra come usare un'istruzione Catch When per filtrare su un'espressione condizionale. Se l'espressione condizionale restituisce True, il codice nel blocco Catch viene eseguito.

Private Sub WhenExample()
    Dim i As Integer = 5

    Try
        Throw New ArgumentException()
    Catch e As OverflowException When i = 5
        Console.WriteLine("First handler")
    Catch e As ArgumentException When i = 4
        Console.WriteLine("Second handler")
    Catch When i = 5
        Console.WriteLine("Third handler")
    End Try
End Sub
' Output: Third handler

Istruzioni Try annidate

Nel seguente esempio è presente un'istruzione Try…Catch contenuta in un blocco Try. Il blocco interno Catch genera un'eccezione con la relativa proprietà InnerException impostata sull'eccezione originale. Il blocco esterno Catch segnala la propria eccezione e l'eccezione interna.

Private Sub InnerExceptionExample()
    Try
        Try
            ' Set a reference to a StringBuilder.
            ' The exception below does not occur if the commented
            ' out statement is used instead.
            Dim sb As System.Text.StringBuilder
            'Dim sb As New System.Text.StringBuilder

            ' Cause a NullReferenceException.
            sb.Append("text")
        Catch ex As Exception
            ' Throw a new exception that has the inner exception
            ' set to the original exception.
            Throw New ApplicationException("Something happened :(", ex)
        End Try
    Catch ex2 As Exception
        ' Show the exception.
        Console.WriteLine("Exception: " & ex2.Message)
        Console.WriteLine(ex2.StackTrace)

        ' Show the inner exception, if one is present.
        If ex2.InnerException IsNot Nothing Then
            Console.WriteLine("Inner Exception: " & ex2.InnerException.Message)
            Console.WriteLine(ex2.StackTrace)
        End If
    End Try
End Sub

Gestione delle eccezioni per metodi asincroni

L'esempio seguente illustra la gestione delle eccezioni per i metodi asincroni. Per intercettare un'eccezione in un'attività asincrona, l'espressione Await si trova in un blocco Try del chiamante e l'eccezione viene intercettata nel blocco Catch.

Rimuovere il commento dalla riga Throw New Exception nell'esempio per illustrare la gestione delle eccezioni. L‘eccezione viene intercettata nel blocco Catch, la proprietà IsFaulted dell'attività viene impostata su True, e la proprietà Exception.InnerException dell'attività viene impostata sull'eccezione.

Rimuovere il commento dalla riga Throw New OperationCancelledException per illustrare cosa accade quando si annulla un processo asincrono. L'eccezione viene intercettata nel blocco Catch e la proprietà IsCanceled dell'attività viene impostata su True. Tuttavia, in alcune condizioni che differiscono da questo esempio, la proprietà IsFaulted dell'attività viene impostata su True e IsCanceled viene impostato su False.

Public Async Function DoSomethingAsync() As Task
    Dim theTask As Task(Of String) = DelayAsync()

    Try
        Dim result As String = Await theTask
        Debug.WriteLine("Result: " & result)
    Catch ex As Exception
        Debug.WriteLine("Exception Message: " & ex.Message)
    End Try

    Debug.WriteLine("Task IsCanceled: " & theTask.IsCanceled)
    Debug.WriteLine("Task IsFaulted:  " & theTask.IsFaulted)
    If theTask.Exception IsNot Nothing Then
        Debug.WriteLine("Task Exception Message: " &
            theTask.Exception.Message)
        Debug.WriteLine("Task Inner Exception Message: " &
            theTask.Exception.InnerException.Message)
    End If
End Function

Private Async Function DelayAsync() As Task(Of String)
    Await Task.Delay(100)

    ' Uncomment each of the following lines to
    ' demonstrate exception handling.

    'Throw New OperationCanceledException("canceled")
    'Throw New Exception("Something happened.")
    Return "Done"
End Function


' Output when no exception is thrown in the awaited method:
'   Result: Done
'   Task IsCanceled: False
'   Task IsFaulted:  False

' Output when an Exception is thrown in the awaited method:
'   Exception Message: Something happened.
'   Task IsCanceled: False
'   Task IsFaulted:  True
'   Task Exception Message: One or more errors occurred.
'   Task Inner Exception Message: Something happened.

' Output when an OperationCanceledException or TaskCanceledException
' is thrown in the awaited method:
'   Exception Message: canceled
'   Task IsCanceled: True
'   Task IsFaulted:  False

Gestione di più eccezioni in metodi asincroni

Il seguente esempio illustra la gestione delle eccezioni dove più attività possono restituire più eccezioni. Il blocco Try ha l'espressione Await per l'attività restituita da Task.WhenAll. L'attività viene completata una volta completate le tre attività a cui si applica Task.WhenAll.

Ognuna delle tre attività genera un'eccezione. Il blocco Catch esegue l'iterazione delle eccezioni presenti nella proprietà Exception.InnerExceptions dell'attività restituita da Task.WhenAll.

Public Async Function DoMultipleAsync() As Task
    Dim theTask1 As Task = ExcAsync(info:="First Task")
    Dim theTask2 As Task = ExcAsync(info:="Second Task")
    Dim theTask3 As Task = ExcAsync(info:="Third Task")

    Dim allTasks As Task = Task.WhenAll(theTask1, theTask2, theTask3)

    Try
        Await allTasks
    Catch ex As Exception
        Debug.WriteLine("Exception: " & ex.Message)
        Debug.WriteLine("Task IsFaulted: " & allTasks.IsFaulted)
        For Each inEx In allTasks.Exception.InnerExceptions
            Debug.WriteLine("Task Inner Exception: " + inEx.Message)
        Next
    End Try
End Function

Private Async Function ExcAsync(info As String) As Task
    Await Task.Delay(100)

    Throw New Exception("Error-" & info)
End Function

' Output:
'   Exception: Error-First Task
'   Task IsFaulted: True
'   Task Inner Exception: Error-First Task
'   Task Inner Exception: Error-Second Task
'   Task Inner Exception: Error-Third Task

Vedi anche