Procedure consigliate per le eccezioniBest practices for exceptions

Un'applicazione progettata correttamente gestisce eccezioni ed errori per impedire arresti anomali dell'applicazione.A well-designed app handles exceptions and errors to prevent app crashes. Questa sezione descrive le procedure consigliate per la gestione e la creazione di eccezioni.This section describes best practices for handling and creating exceptions.

Usare blocchi try/catch/finallyUse try/catch/finally blocks

Usare blocchi try/catch/finally nel codice che può potenzialmente generare un'eccezione.Use try/catch/finally blocks around code that can potentially generate an exception.

Ordinare sempre le eccezioni in blocchi catch dalla più specifica alla meno specifica.In catch blocks, always order exceptions from the most specific to the least specific.

Usare un blocco finally per pulire le risorse, indipendentemente dalla possibilità di ripristino.Use a finally block to clean up resources, whether you can recover or not.

Gestire le condizioni comuni senza generare eccezioniHandle common conditions without throwing exceptions

È consigliabile gestire le condizioni che potrebbero verificarsi ma potrebbero generare un'eccezione in modo da evitare l'eccezione.For conditions that are likely to occur but might trigger an exception, consider handling them in a way that will avoid the exception. Ad esempio, se si tenta di chiudere una connessione già chiusa, si otterrà InvalidOperationException.For example, if you try to close a connection that is already closed, you'll get an InvalidOperationException. Per impedire che ciò accada, usare un'istruzione if per verificare lo stato della connessione prima di tentare di chiuderla.You can avoid that by using an if statement to check the connection state before trying to close it.

if (conn->State != ConnectionState::Closed)
{
    conn->Close();
}
if (conn.State != ConnectionState.Closed)
{
    conn.Close();
}
If conn.State <> ConnectionState.Closed Then
    conn.Close()
End IF

Se prima della chiusura non viene verificato lo stato della connessione, è possibile rilevare l'eccezione InvalidOperationException.If you don't check connection state before closing, you can catch the InvalidOperationException exception.

try
{
    conn->Close();
}
catch (InvalidOperationException^ ex)
{
    Console::WriteLine(ex->GetType()->FullName);
    Console::WriteLine(ex->Message);
}
try
{
    conn.Close();
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.GetType().FullName);
    Console.WriteLine(ex.Message);
}
Try
    conn.Close()
Catch ex As InvalidOperationException
    Console.WriteLine(ex.GetType().FullName)
    Console.WriteLine(ex.Message)
End Try

Nella scelta del metodo è necessario considerare la frequenza con cui si prevede che l'evento possa verificarsi.The method to choose depends on how often you expect the event to occur.

  • Usare la gestione delle eccezioni se l'evento non si verifica molto spesso, ovvero, se l'evento è davvero eccezionale e indica un errore quale la fine imprevista di un file.Use exception handling if the event doesn't occur very often, that is, if the event is truly exceptional and indicates an error (such as an unexpected end-of-file). Quando si utilizza la gestione delle eccezioni, una minore quantità di codice viene eseguita in condizioni normali.When you use exception handling, less code is executed in normal conditions.

  • Ricercare le condizioni di errore nel codice se l'evento si verifica ripetutamente e può essere considerato parte dell'esecuzione normale.Check for error conditions in code if the event happens routinely and could be considered part of normal execution. Quando si ricercano le condizioni di errore comuni, viene eseguita una minore quantità di codice poiché vengono evitate le eccezioni.When you check for common error conditions, less code is executed because you avoid exceptions.

Progettare le classi in modo da evitare le eccezioniDesign classes so that exceptions can be avoided

Una classe può offrire metodi o proprietà che consentono di evitare di effettuare una chiamata che potrebbe generare un'eccezione.A class can provide methods or properties that enable you to avoid making a call that would trigger an exception. Con la classe FileStream, ad esempio, sono disponibili metodi che consentono di determinare se è stata raggiunta la fine del file.For example, a FileStream class provides methods that help determine whether the end of the file has been reached. I metodi possono essere usati per evitare l'eccezione che verrebbe generata se si continua la lettura oltre la fine del file.These can be used to avoid the exception that is thrown if you read past the end of the file. L'esempio seguente illustra come continuare la lettura fino alla fine di un file senza generare un'eccezione.The following example shows how to read to the end of a file without triggering an exception.

class FileRead
{
public:
    void ReadAll(FileStream^ fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == nullptr)
        {
            throw gcnew System::ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead->Seek(0, SeekOrigin::Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead->Length; i++)
        {
            b = fileToRead->ReadByte();
            Console::Write(b.ToString());
            // Or do something else with the byte.
        }
    }
};
class FileRead
{
    public void ReadAll(FileStream fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == null)
        {
            throw new System.ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead.Length; i++)
        {
            b = fileToRead.ReadByte();
            Console.Write(b.ToString());
            // Or do something else with the byte.
        }
    }
}
Class FileRead
    Public Sub ReadAll(fileToRead As FileStream)
        ' This if statement is optional
        ' as it is very unlikely that
        ' the stream would ever be null.
        If fileToRead Is Nothing Then
            Throw New System.ArgumentNullException()
        End If

        Dim b As Integer

        ' Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin)

        ' Read each byte to the end of the file.
        For i As Integer = 0 To fileToRead.Length - 1
            b = fileToRead.ReadByte()
            Console.Write(b.ToString())
            ' Or do something else with the byte.
        Next i
    End Sub
End Class

Un altro metodo per evitare le eccezioni consiste nel restituire il valore Null per i casi di errore estremamente comuni anziché generare un'eccezione.Another way to avoid exceptions is to return null for extremely common error cases instead of throwing an exception. Un caso di errore estremamente comune può essere considerato come un normale flusso di controllo.An extremely common error case can be considered normal flow of control. Restituendo Null in questi casi, si riduce l'impatto sulle prestazioni di un'applicazione.By returning null in these cases, you minimize the performance impact to an app.

Generare eccezioni anziché restituire un codice di erroreThrow exceptions instead of returning an error code

Le eccezioni garantiscono il rilevamento degli errori quando il codice chiamante non rileva un codice restituito.Exceptions ensure that failures do not go unnoticed because calling code didn't check a return code.

Usare i tipi di eccezione .NET predefinitiUse the predefined .NET exception types

Introdurre una nuova classe di eccezioni solo quando non è possibile applicare una classe predefinita.Introduce a new exception class only when a predefined one doesn't apply. Ad esempio:For example:

Terminare i nomi delle classi di eccezioni con la parola ExceptionEnd exception class names with the word Exception

Quando è necessaria un'eccezione personalizzata, assegnare un nome appropriato all'eccezione e derivarla dalla classe Exception.When a custom exception is necessary, name it appropriately and derive it from the Exception class. Ad esempio:For example:

public ref class MyFileNotFoundException : public Exception
{
};
public class MyFileNotFoundException : Exception
{
}
Public Class MyFileNotFoundException
    Inherits Exception
End Class

Inserire tre costruttori nelle classi di eccezioni personalizzateInclude three constructors in custom exception classes

Usare almeno i tre costruttori comuni quando si creano classi di eccezione personalizzate: il costruttore predefinito, un costruttore che accetta un messaggio stringa e un costruttore che accetta un messaggio stringa e un'eccezione interna.Use at least the three common constructors when creating your own exception classes: the default constructor, a constructor that takes a string message, and a constructor that takes a string message and an inner exception.

Per un esempio, vedere Procedura: Creare eccezioni definite dall'utente.For an example, see How to: Create User-Defined Exceptions.

Garantire la disponibilità dei dati dell'eccezione per il codice eseguito in modalità remotaEnsure that exception data is available when code executes remotely

Quando si creano eccezioni definite dall'utente, garantire che i metadati relativi alle eccezioni siano disponibili per il codice eseguito in modalità remota.When you create user-defined exceptions, ensure that the metadata for the exceptions is available to code that is executing remotely.

Ad esempio, nelle implementazioni .NET che supportano domini app, è possibile che si verifichino eccezioni nei domini app.For example, on .NET implementations that support App Domains, exceptions may occur across App domains. Si supponga che il dominio app A crei il dominio app B che esegue codice che genera un'eccezione.Suppose App Domain A creates App Domain B, which executes code that throws an exception. Per rilevare e gestire correttamente l'eccezione è necessario che il dominio app A sia in grado di individuare l'assembly contenente l'eccezione generata dal dominio app B. Se il dominio app B genera un'eccezione contenuta in un assembly nella relativa base dell'applicazione ma non nella base dell'applicazione del dominio app A, il dominio app A non sarà in grado di individuare l'eccezione e Common Language Runtime genererà un'eccezione FileNotFoundException.For App Domain A to properly catch and handle the exception, it must be able to find the assembly that contains the exception thrown by App Domain B. If App Domain B throws an exception that is contained in an assembly under its application base, but not under App Domain A's application base, App Domain A will not be able to find the exception, and the common language runtime will throw a FileNotFoundException exception. Per evitare che questo si verifichi è possibile distribuire l'assembly contenente le informazioni sull'eccezione in due modi:To avoid this situation, you can deploy the assembly that contains the exception information in two ways:

  • Inserendo l'assembly in una base applicativa comune condivisa da entrambi i domini applicazionePut the assembly into a common application base shared by both app domains.

    - oppure -- or -

  • Se i domini non condividono alcuna base applicativa comune, firmando l'assembly contenente le informazioni sull'eccezione con un nome sicuro e distribuendo tale assembly nella Global Assembly Cache.If the domains do not share a common application base, sign the assembly that contains the exception information with a strong name and deploy the assembly into the global assembly cache.

Usare messaggi di errore grammaticalmente correttiUse grammatically correct error messages

Scrivere frasi chiare e includere la punteggiatura finale.Write clear sentences and include ending punctuation. Ogni frase della stringa assegnata alla proprietà Exception.Message deve terminare con un punto.Each sentence in the string assigned to the Exception.Message property should end in a period. Ad esempio, "Overflow della tabella del log."For example, "The log table has overflowed." è una stringa del messaggio corretta.would be an appropriate message string.

Includere in ogni eccezione un messaggio stringa localizzatoInclude a localized string message in every exception

Il messaggio di errore visualizzato all'utente è derivato dalla proprietà Exception.Message dell'eccezione generata e non dal nome della classe di eccezione.The error message that the user sees is derived from the Exception.Message property of the exception that was thrown, and not from the name of the exception class. In genere, si assegna un valore alla proprietà Exception.Message passando la stringa del messaggio all'argomento message di un costruttore di eccezione.Typically, you assign a value to the Exception.Message property by passing the message string to the message argument of an Exception constructor.

Per le applicazioni localizzate, è necessario specificare una stringa di messaggio localizzata per ogni eccezione che può essere generata dall'applicazione.For localized applications, you should provide a localized message string for every exception that your application can throw. Usare i file di risorse per specificare i messaggi di errore localizzati.You use resource files to provide localized error messages. Per informazioni sulla localizzazione delle applicazioni e sul recupero delle stringhe localizzate, vedere Risorse nelle applicazioni desktop e System.Resources.ResourceManager.For information on localizing applications and retrieving localized strings, see Resources in Desktop Apps and System.Resources.ResourceManager.

Nelle eccezioni personalizzate specificare le proprietà aggiuntive necessarieIn custom exceptions, provide additional properties as needed

Specificare le proprietà aggiuntive di un'eccezione (oltre alla stringa del messaggio personalizzata) solo in un contesto di codice in cui è utile avere a disposizione altre informazioni.Provide additional properties for an exception (in addition to the custom message string) only when there's a programmatic scenario where the additional information is useful. Ad esempio, FileNotFoundException fornisce la proprietà FileName.For example, the FileNotFoundException provides the FileName property.

Inserire istruzioni throw in modo che l'analisi dello stack risulti utilePlace throw statements so that the stack trace will be helpful

La traccia dello stack inizia in corrispondenza dell'istruzione in cui l'eccezione viene generata e termina in corrispondenza dell'istruzione catch che intercetta l'eccezione.The stack trace begins at the statement where the exception is thrown and ends at the catch statement that catches the exception.

Usare metodi per la creazione di eccezioniUse exception builder methods

Una classe genera spesso la stessa eccezione da punti diversi dell'implementazione.It is common for a class to throw the same exception from different places in its implementation. Per evitare codice di dimensioni eccessive, utilizzare metodi di supporto che creano l'eccezione e la restituiscono.To avoid excessive code, use helper methods that create the exception and return it. Ad esempio:For example:

ref class FileReader
{
private:
    String^ fileName;

public:
    FileReader(String^ path)
    {
        fileName = path;
    }

    array<Byte>^ Read(int bytes)
    {
        array<Byte>^ results = FileUtils::ReadFromFile(fileName, bytes);
        if (results == nullptr)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException^ NewFileIOException()
    {
        String^ description = "My NewFileIOException Description";

        return gcnew FileReaderException(description);
    }
};
class FileReader
{
    private string fileName;

    public FileReader(string path)
    {
        fileName = path;
    }

    public byte[] Read(int bytes)
    {
        byte[] results = FileUtils.ReadFromFile(fileName, bytes);
        if (results == null)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException NewFileIOException()
    {
        string description = "My NewFileIOException Description";

        return new FileReaderException(description);
    }
}
Class FileReader
    Private fileName As String

    
    Public Sub New(path As String)
        fileName = path
    End Sub

    Public Function Read(bytes As Integer) As Byte()
        Dim results() As Byte = FileUtils.ReadFromFile(fileName, bytes)
        If results Is Nothing
            Throw NewFileIOException()
        End If
        Return results
    End Function

    Function NewFileIOException() As FileReaderException
        Dim description As String = "My NewFileIOException Description"

        Return New FileReaderException(description)
    End Function
End Class

In alcuni casi è preferibile usare il costruttore dell'eccezione per compilare l'eccezione.In some cases, it's more appropriate to use the exception's constructor to build the exception. Un esempio è una classe di eccezioni globali, ad esempio ArgumentException.An example is a global exception class such as ArgumentException.

Eliminare i risultati intermedi quando si genera un'eccezioneClean up intermediate results when throwing an exception

I chiamanti dovrebbero avere la garanzia che non si verifichino effetti secondari quando un'eccezione viene generata da un metodo.Callers should be able to assume that there are no side effects when an exception is thrown from a method. Ad esempio, se è presente un codice che trasferisce denaro prelevandolo da un conto e depositandolo in un altro conto e viene generata un'eccezione durante l'esecuzione del deposito, non si desidera che il prelievo rimanga attivo.For example, if you have code that transfers money by withdrawing from one account and depositing in another account, and an exception is thrown while executing the deposit, you don't want the withdrawal to remain in effect.

public void TransferFunds(Account from, Account to, decimal amount)
{
    from.Withdrawal(amount);
    // If the deposit fails, the withdrawal shouldn't remain in effect. 
    to.Deposit(amount);
}

Un modo per gestire questa situazione consiste nel rilevare eventuali eccezioni generate dalla transazione di deposito e annullare il prelievo.One way to handle this situation is to catch any exceptions thrown by the deposit transaction and roll back the withdrawal.

private static void TransferFunds(Account from, Account to, decimal amount)
{
    string withdrawalTrxID = from.Withdrawal(amount);
    try
    {
        to.Deposit(amount);
    }
    catch
    {
        from.RollbackTransaction(withdrawalTrxID);
        throw;
    }
}

Questo esempio illustra l'uso di throw per generare nuovamente l'eccezione originale rendendo in questo modo più semplice per i chiamanti visualizzare la causa effettiva del problema senza dover esaminare la proprietà InnerException.This example illustrates the use of throw to re-throw the original exception, which can make it easier for callers to see the real cause of the problem without having to examine the InnerException property. In alternativa è possibile generare una nuova eccezione e includere l'eccezione originale come eccezione interna:An alternative is to throw a new exception and include the original exception as the inner exception:

catch (Exception ex)
{
    from.RollbackTransaction(withdrawalTrxID);
    throw new Exception("Withdrawal failed", ex);
}

Vedere ancheSee Also

EccezioniExceptions