English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Gestione delle eccezioni di C#

In questo corso, imparerai a gestire le eccezioni in C# utilizzando i blocchi try, catch e finally.

Occorre gestire le eccezioni nelle applicazioni per prevenire il crash del programma e risultati imprevisti, registrare le eccezioni e continuare a eseguire altre funzioni. C# fornisce supporto integrato per gestire le eccezioni utilizzando i blocchi try, catch e finally.

Sintassi:

try
{
    // Mettere qui il codice potrebbe causare un'eccezione
}
catch
{
    // Gestire qui l'eccezione
}
finally
{
    // Codice di pulizia finale
}

Blocco try:Qualsiasi codice sospetto che potrebbe causare un'eccezione dovrebbe essere messo in un blocco try{ }. Durante l'esecuzione, se si verifica un'eccezione, il flusso di controllo salta al primo blocco catch corrispondente.

catch Blocco:Il blocco catch è un blocco di gestione delle eccezioni dove è possibile eseguire alcune operazioni, come la registrazione e l'audit delle eccezioni. Il blocco catch accetta un parametro di tipo di eccezione, che può essere utilizzato per ottenere dettagli dell'eccezione.

finally Blocco:Il blocco finally viene sempre eseguito, indipendentemente dal fatto che si verifichi o meno un'eccezione. Di solito, il blocco finally dovrebbe essere utilizzato per rilasciare risorse, ad esempio chiudere qualsiasi flusso o oggetto file aperto nel blocco try.

Se inserisci un carattere non numerico, il seguente contenuto potrebbe causare un'eccezione.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Inserisci un numero: ");
        var num = int.Parse(Console.ReadLine());
        Console.WriteLine($"Il quadrato di {num} è {num * num}");
    }
}

Per gestire le possibili eccezioni nell'esempio sopra, avvolgere il codice in un blocco try e poi gestire l'eccezione nel blocco catch, come mostrato di seguito.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Inserisci un numero: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"Il quadrato di {num} è {num * num}");
        }
        catch
        {
            Console.Write("Si è verificato un errore.");
        }
        finally
        {
            Console.Write("Riprova con un numero diverso.");
        }
    }
}

Nell'esempio sopra, abbiamo avvolto questo codice in un blocco try. Se si verifica un'eccezione all'interno del blocco try, il programma passerà al blocco catch. All'interno del blocco catch, mostreremo un messaggio all'utente per informarlo dell'errore, e nel blocco finally, mostreremo un messaggio riguardante le operazioni eseguite dopo l'esecuzione del programma.

Il blocco try deve essere seguito da un blocco catch o finally o da entrambi. Se il blocco try non utilizza un blocco catch o finally, verrà generato un errore durante la compilazione.

Nella situazione ideale, il blocco catch dovrebbe includere i parametri di una classe di eccezione nativa o personalizzata per ottenere dettagli di errore. Di seguito è inclusa l'eccezione Exception che cattura tutti i tipi di eccezioni con il parametro type.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Inserisci un numero: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"Il quadrato di {num} è {num * num}");
        }
        catch(Exception ex)
        {
            Console.Write("Info errore: " + ex.Message);
        }
        finally
        {
            Console.Write("Riprova con un numero diverso.");
        }
    }
}

Filtro di eccezione

Puoi usare più blocchi catch con parametri di tipo di eccezione diverso. Questo si chiama filtro di eccezione. È molto utile quando si desidera gestire diversi tipi di eccezioni in modo diverso.

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Inserisci un numero da dividere per 100: ");
        
        try
        {
            int num = int.Parse(Console.ReadLine());
            int result = 100 / num;
            Console.WriteLine("100 / {0} = {1}", num, result);
        }
        catch(DivideByZeroException ex)
        {
            Console.Write("Non può essere diviso per zero. Prova di nuovo.");
        }
        catch(InvalidOperationException ex)
        {
            Console.Write("Operazione non valida. Prova di nuovo.");
        }
        catch(FormatException  ex)
        {
            Console.Write("Formato non valido. Prova di nuovo.");
        }
        catch(Exception  ex)
        {
            Console.Write("Si è verificato un errore! Prova di nuovo.");
        }
    }
}

Nell'esempio sopra, abbiamo specificato più blocchi catch con diversi tipi di eccezioni. Possiamo mostrare al utente un messaggio appropriato in base all'errore, in modo che l'utente non ripeta lo stesso errore.

Attenzione:
Non è permesso avere più di un blocco catch con lo stesso tipo di eccezione. Il blocco catch con il tipo di eccezione base deve essere l'ultimo blocco.

Blocco catch non valido

Non è permesso utilizzare un blocco catch senza parametri e un blocco catch con parametri Exception nello stesso try..catch, perché entrambi eseguono la stessa operazione.

try
{
    // Codice che potrebbe generare un'eccezione
}
catch // Non può avere contemporaneamente catch e catch(Exception 异常)
{ 
    Console.WriteLine("Occorso un'eccezione");
}
catch(Exception ex) // Non può avere contemporaneamente catch e catch(异常异常)
{
    Console.WriteLine("Occorso un'eccezione");
}

Inoltre, il blocco catch senza parametri catch {} o il blocco catch universale catch (Exception ex){} devono essere l'ultimo blocco. Se dopo il blocco catch {} o catch (Exception ex) ci sono altri blocchi catch, il compilatore genererà un errore.

    Esempio: cattura catch non valida

try
{
    // Codice che potrebbe generare un'eccezione
}
catch
{ 
    // Questo blocco catch deve essere l'ultimo
}
catch (NullReferenceException nullEx)
{
    Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
    Console.WriteLine(inEx.Message);
}

blocco finally

Il blocco finally è un blocco opzionale che deve essere posizionato dopo il blocco try o catch. Il blocco finally viene sempre eseguito, indipendentemente dal fatto che si verifichi o meno un'eccezione. Il blocco finally viene spesso utilizzato per codice di pulizia, ad esempio per gestire oggetti non gestiti.

    Esempio: blocco finally

static void Main(string[] args)
{
    FileInfo file = null;
    try
    {
        Console.Write("Enter a file name to write: ");
        string fileName = Console.ReadLine();
        file = new FileInfo(fileName);
        file.AppendText("Hello World!")
    }
    catch(Exception ex)
    {
        Console.WriteLine("Error occurred: {0}", ex.Message);
    }
    finally
    {
        // Ecco come pulire l'oggetto file;
        file = null;
    }
}
finally non può essere utilizzato più blocchi. Inoltre, il blocco finally non può contenere le parole chiave return, continue o break. Non permette di abbandonare il blocco finally.

try-catch annidato

C# permette di annidare blocchi try-catch. Quando si utilizzano blocchi try-catch annidati, l'eccezione viene catturata nel primo blocco corrispondente dopo il blocco try in cui si verifica l'eccezione catch.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch
        {
            Console.WriteLine("catch interno");
        }
    }
    catch
    {
        Console.WriteLine("catch esterno");
    }
}
Output:
catch interno

catch nell'esempio sopra, eseguirà un blocco interno perché è il primo blocco che gestisce tutte le eccezioni.

Se non c'è un blocco catch interno che corrisponde al tipo di eccezione lanciata, il controllo passerà al blocco catch esterno fino a trovare un filtro di eccezione appropriato. Vedi l'esempio seguente.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch(NullReferenceException ex)
        {
            Console.WriteLine("catch interno");
        }
    }
    catch
    {
        Console.WriteLine("catch esterno");
    }
}
Output:
catch esterno

Negli esempi sopra, verrà sollevata l'eccezione di tipo DivideByZeroException. Poiché il blocco catch interno gestisce solo NullReferenceTypeException, il blocco catch esterno lo gestirà.