try-catch (Riferimenti per C#)
L'istruzione try-catch è costituita da un blocco try seguito da una o più clausole catch che specificano gestori per diverse eccezioni.
Note
Quando viene generata un'eccezione, Common Language Runtime (CLR) cerca l'istruzione catch che gestisce l'eccezione indicata. Se il metodo in esecuzione non contiene tale blocco catch, CLR analizza il metodo che ha chiamato il metodo corrente e così via lungo lo stack di chiamate. Se non viene trovato alcun blocco catch, CLR visualizza un messaggio di eccezione non gestita all'utente e interrompe l'esecuzione del programma.
Il blocco try contiene il codice controllato che può generare l'eccezione. Il blocco viene eseguito fino a quando non viene generata un'eccezione o fino al corretto completamento dell'esecuzione. Ad esempio, il tentativo riportato di seguito di eseguire il cast di un oggetto null genera l'eccezione NullReferenceException:
object o2 = null;
try
{
int i2 = (int)o2; // Error
}
Anche se la clausola catch può essere utilizzata senza argomenti per rilevare qualsiasi tipo di eccezione, questo utilizzo non viene consigliato. In generale, è opportuno rilevare solo le eccezioni per le quali si conosce la modalità di recupero. Pertanto, è consigliabile specificare sempre un argomento oggetto derivato da Exception, ad esempio:
catch (InvalidCastException e)
{
}
È possibile utilizzare più di una clausola catch specifica nella stessa istruzione try-catch. In questo caso, l'ordine delle clausole catch è importante poiché le clausole catch vengono esaminate nell'ordine specificato. Vengono intercettate prima le eccezioni più specifiche, quindi quelle meno specifiche. Il compilatore produce un errore se si ordinano i blocchi catch in modo tale da non poter raggiungere mai un blocco successivo.
Un'istruzione throw può essere utilizzata in un blocco catch per rigenerare l'eccezione intercettata dall'istruzione catch. Nel seguente esempio vengono estratte le informazioni di origine da un'eccezione IOException e quindi generata l'eccezione nel metodo padre.
catch (FileNotFoundException e)
{
// FileNotFoundExceptions are handled here.
}
catch (IOException e)
{
// Extract some information from this exception, and then
// throw it to the parent method.
if (e.Source != null)
Console.WriteLine("IOException source: {0}", e.Source);
throw;
}
È possibile intercettare un'eccezione e generare un'eccezione diversa. In tal caso, specificare l'eccezione che è stata catturata come eccezione interna, come illustrato nell'esempio seguente.
catch (InvalidCastException e)
{
// Perform some action here, and then throw a new exception.
throw new YourCustomException("Put your error message here.", e);
}
È inoltre possibile generare nuovamente un'eccezione quando una condizione specifica è vera, come illustrato nell'esempio seguente.
catch (InvalidCastException e)
{
if (e.Data == null)
{
throw;
}
else
{
// Take some action.
}
}
All'interno di un blocco try, inizializzare solo le variabili che vengono dichiarate al suo interno. In caso contrario, un'eccezione può verificarsi prima del completamento dell'esecuzione del blocco. Nell'esempio di codice riportato di seguito, ad esempio, la variabile n viene inizializzata all'interno del blocco try. Un tentativo di utilizzare questa variabile all'esterno del blocco try nell'istruzione Write(n) genera un errore del compilatore.
static void Main()
{
int n;
try
{
// Do not initialize this variable here.
n = 123;
}
catch
{
}
// Error: Use of unassigned local variable 'n'.
Console.Write(n);
}
Per ulteriori informazioni sulla clausola catch, vedere try-catch-finally.
Eccezioni nei metodi di Async
Un metodo asincrono viene contrassegnato da un modificatore async e in genere contiene uno o più attesa espressioni o istruzioni. Un'espressione di attesa applica l'operatore attendere a Task o a Task. Un'espressione await non può verificarsi in un blocco catch o in un blocco finally.
Quando il controllo raggiunge await nel metodo async, lo stato di avanzamento nel metodo viene sospeso finché l'attività attesa non completi. Quando l'attività è stata completata, l'esecuzione può riattivare il metodo. Per ulteriori informazioni, vedere Programmazione asincrona con Async e Await (C# e Visual Basic) e Flusso di controllo in programmi asincroni (C# e Visual Basic).
L'attività completata a cui si applica await potrebbe essere nello stato Faulted a causa di un'eccezione non gestita nel metodo che restituisce l'attività. In attesa di un'attività genera un'eccezione. Un'attività può inoltre finalizzare in uno stato annullato se il processo asincrono che restituisce viene annullato. Attesa di un'attività annullata generato OperationCanceledException. Per ulteriori informazioni su come annullare un processo asincrono, vedere Ottimizzazione dell'applicazione Async (C# e Visual Basic).
Per rilevare l'eccezione, attendere l'attività in un blocco try e rilevare l'eccezione nel blocco collegato catch. Per un esempio, vedere la sezione “esempio„.
Un'attività può essere in uno stato di errore perché più eccezioni sono state apportate nel metodo atteso async. Ad esempio, un'attività potrebbe essere il risultato di una chiamata a Task.WhenAll. Quando si attendono tale attività, una sola delle eccezioni viene intercettata e non è possibile prevedere quale eccezione viene intercettata. Per un esempio, vedere la sezione “esempio„.
Esempio
Negli esempi seguenti, il blocco try contiene una chiamata al metodo ProcessString che potrebbe causare un'eccezione. La clausola catch contiene il gestore eccezioni che consente semplicemente di visualizzare un messaggio sullo schermo. Quando l'istruzione throw viene chiamata dall'interno di MyMethod, il sistema cerca l'istruzione catch e visualizza il messaggio Exception caught.
class TryFinallyTest
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
static void Main()
{
string s = null; // For demonstration purposes.
try
{
ProcessString(s);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
}
/*
Output:
System.ArgumentNullException: Value cannot be null.
at TryFinallyTest.Main() Exception caught.
* */
Nell'esempio seguente, due blocchi catch vengono utilizzati e eccezione più specifica, che viene prima, viene intercettata.
Per intercettare la meno un'eccezione specifica, è possibile sostituire l'istruzione throw in ProcessString con l'istruzione seguente: throw new Exception().
Se si inserisce il blocco catch meno- specifico prima nell'esempio, il seguente messaggio di errore: A previous catch clause already catches all exceptions of this or a super type ('System.Exception').
class ThrowTest3
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
static void Main()
{
try
{
string s = null;
ProcessString(s);
}
// Most specific:
catch (ArgumentNullException e)
{
Console.WriteLine("{0} First exception caught.", e);
}
// Least specific:
catch (Exception e)
{
Console.WriteLine("{0} Second exception caught.", e);
}
}
}
/*
Output:
System.ArgumentNullException: Value cannot be null.
at Test.ThrowTest3.ProcessString(String s) ... First exception caught.
*/
Il seguente esempio viene illustrata la gestione delle eccezioni per i metodi async. Per intercettare un'eccezione che generata l'eccezione di un'attività async, posizionano l'espressione await in un blocco try e intercetta l'eccezione in un blocco catch.
Rimuovere il commento dalla riga throw new Exception nell'esempio per illustrare la gestione delle eccezioni. La proprietà IsFaulted dell'attività è impostata su True, la proprietà Exception.InnerException dell'attività viene impostata sull'eccezione e l'eccezione viene rilevata nel blocco catch.
Rimuovere il commento dalla riga throw new OperationCancelledException per illustrare ciò che si verifica quando il processo asincrono cancelan. La proprietà IsCanceled dell'attività è impostata su truee l'eccezione viene rilevata nel blocco catch. In alcuni casi non si applicano a questo esempio, la proprietà IsFaulted dell'attività è impostata su true e IsCanceled è impostato su false.
public async Task DoSomethingAsync()
{
Task<string> theTask = DelayAsync();
try
{
string result = await theTask;
Debug.WriteLine("Result: " + result);
}
catch (Exception ex)
{
Debug.WriteLine("Exception Message: " + ex.Message);
}
Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
Debug.WriteLine("Task IsFaulted: " + theTask.IsFaulted);
if (theTask.Exception != null)
{
Debug.WriteLine("Task Exception Message: "
+ theTask.Exception.Message);
Debug.WriteLine("Task Inner Exception Message: "
+ theTask.Exception.InnerException.Message);
}
}
private async Task<string> DelayAsync()
{
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";
}
// 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 a OperationCanceledException or TaskCanceledException
// is thrown in the awaited method:
// Exception Message: canceled
// Task IsCanceled: True
// Task IsFaulted: False
Il seguente esempio viene illustrata la gestione delle eccezioni in cui più attività possono comportare più eccezioni. Il blocco try attendere l'attività restituita da una chiamata a Task.WhenAll. L'attività è completa quando le tre attività a cui si applica WhenAll sono state completate.
Ciascuna delle cause di attività un'eccezione. Il blocco catch scorre le eccezioni, che si trovano nella proprietà Exception.InnerExceptions dell'attività che è stata restituita da Task.WhenAll.
public async Task DoMultipleAsync()
{
Task theTask1 = ExcAsync(info: "First Task");
Task theTask2 = ExcAsync(info: "Second Task");
Task theTask3 = ExcAsync(info: "Third Task");
Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);
try
{
await allTasks;
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.Message);
Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
foreach (var inEx in allTasks.Exception.InnerExceptions)
{
Debug.WriteLine("Task Inner Exception: " + inEx.Message);
}
}
}
private async Task ExcAsync(string info)
{
await Task.Delay(100);
throw new Exception("Error-" + info);
}
// 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
Specifiche del linguaggio C#
Per altre informazioni, vedere la Specifiche del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.
Vedere anche
Attività
Procedura: generare eccezioni in modo esplicito
Riferimenti
Istruzioni try, throw e catch (C++)
Istruzioni di gestione delle eccezioni (Riferimenti per C#)
try...finally (Riferimenti per C#)