Condividi tramite


Gestione delle eccezioni (Guida per programmatori C#)

Un blocco try viene usato dai programmatori C# per partizionare il codice che potrebbe essere interessato da un'eccezione. I blocchi catch associati vengono usati per gestire eventuali eccezioni risultanti. Un blocco finally contiene codice che viene eseguito indipendentemente dal fatto che venga generata o meno un'eccezione nel blocco try, come, ad esempio, il rilascio delle risorse allocate nel blocco try. Un try blocco richiede uno o più blocchi associati catch o un finally blocco o entrambi.

Negli esempi seguenti viene mostrata un'istruzione try-catch , un'istruzione try-finally e un'istruzione try-catch-finally .

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

Un try blocco senza un catch blocco o un finally blocco provoca un errore del compilatore.

Blocchi catch

Un catch blocco può specificare il tipo di eccezione da intercettare. La specifica del tipo è denominata filtro eccezioni. Il tipo di eccezione deve essere derivato da Exception. In generale, non specificare Exception come filtro eccezioni, a meno che non si sappia come gestire tutte le eccezioni che potrebbero essere generate nel blocco try, o se è stata inclusa una dichiarazione throw alla fine del blocco catch.

È possibile concatenare più catch blocchi con classi di eccezione diverse. I catch blocchi vengono valutati dall'alto verso il basso nel codice, ma viene eseguito un catch solo blocco per ogni eccezione generata. Viene eseguito il primo catch blocco che specifica il tipo esatto o una classe base dell'eccezione generata. Se nessun blocco catch specifica una classe di eccezione corrispondente, viene selezionato un blocco catch che non dispone di alcun tipo, se presente nella dichiarazione. È importante posizionare i blocchi catch con le classi di eccezioni più specifiche (ovvero le classi di eccezioni più derivate).

Catturare le eccezioni quando le condizioni seguenti sono vere:

  • Si ha una buona conoscenza del motivo per cui l'eccezione potrebbe essere generata e è possibile implementare un ripristino specifico, ad esempio richiedendo all'utente di immettere un nuovo nome di file quando si intercetta un FileNotFoundException oggetto.
  • È possibile creare e generare una nuova eccezione più specifica.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • Si vuole gestire parzialmente un'eccezione prima di passarla per una gestione più approfondita. Nell'esempio seguente viene usato un catch blocco per aggiungere una voce a un log degli errori prima di rigenerare l'eccezione.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

È anche possibile specificare filtri eccezioni per aggiungere un'espressione booleana a una clausola catch. I filtri eccezioni indicano che una clausola catch specifica venga soddisfatta solo quando tale condizione è vera. Nell'esempio seguente entrambe le clausole catch usano la stessa classe di eccezione, ma viene verificata una condizione aggiuntiva per creare un messaggio di errore diverso:

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

Un filtro eccezioni che restituisce false sempre può essere usato per esaminare tutte le eccezioni, ma non elaborarle. Un uso tipico consiste nel registrare le eccezioni:

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

Il LogException metodo restituisce sempre false, nessuna catch clausola corrisponde a questo filtro di eccezioni. La clausola catch può essere generale, usando System.Exceptione le clausole successive possono elaborare classi di eccezioni più specifiche.

Blocchi finally

Un finally blocco consente di pulire le azioni eseguite in un try blocco. Se presente, il finally blocco viene eseguito per ultimo, dopo il try blocco e qualsiasi blocco corrispondente catch . Viene sempre eseguito un finally blocco, indipendentemente dal fatto che venga generata un'eccezione o che venga trovato un catch blocco corrispondente al tipo di eccezione.

Il finally blocco può essere usato per rilasciare risorse come flussi di file, connessioni di database e handle grafici senza attendere che il Garbage Collector nel runtime finalizzi gli oggetti.

Nell'esempio seguente il finally blocco viene usato per chiudere un file aperto nel try blocco . Si noti che lo stato dell'handle di file viene controllato prima della chiusura del file. Se il try blocco non riesce ad aprire il file, l'handle di file ha ancora il valore null e il finally blocco non tenta di chiuderlo. Se invece il file viene aperto correttamente nel try blocco, il finally blocco chiude il file aperto.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

Specifiche del linguaggio C#

Per altre informazioni, vedere Eccezioni e Istruzione try nella specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedere anche