Ricerca…


Osservazioni

Relazionato:

Cattura un'eccezione

Il codice può e deve generare eccezioni in circostanze eccezionali. Esempi di questo includono:

Il chiamante può gestire queste eccezioni "catturandole" e dovrebbe farlo solo quando:

  • Può effettivamente risolvere la circostanza eccezionale o recuperare in modo appropriato, oppure;
  • Può fornire un contesto aggiuntivo all'eccezione che sarebbe utile se l'eccezione deve essere ripetuta (le eccezioni ridistribuite vengono catturate dai gestori di eccezioni più in alto nello stack di chiamate)

Va notato che la scelta di non prendere un'eccezione è perfettamente valida se l'intenzione è quella di essere gestita ad un livello più alto.

La cattura di un'eccezione viene eseguita avvolgendo il codice potenzialmente lancio in un blocco try { ... } come segue e rilevando le eccezioni che è in grado di gestire in un catch (ExceptionType) { ... } :

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}

Usando un blocco finalmente

Il blocco finally { ... } di try-finally o try-catch-finally verrà sempre eseguito, indipendentemente dal fatto che si sia verificata o meno un'eccezione (tranne quando è stata generata una StackOverflowException o è stata effettuata una chiamata a Environment.FailFast() ).

Può essere utilizzato per liberare o ripulire le risorse acquisite nel blocco try { ... } modo sicuro.

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream = null;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
    if (fileStream != null)
    {
        fileStream.Dispose();
    }
}

Cattura e rilancio hanno catturato eccezioni

Quando si desidera rilevare un'eccezione e fare qualcosa, ma non è possibile continuare l'esecuzione del blocco di codice corrente a causa dell'eccezione, è possibile che si desideri rilanciare l'eccezione al successivo gestore di eccezioni nello stack di chiamate. Ci sono buoni modi e cattivi modi per farlo.

private static void AskTheUltimateQuestion()
{
    try
    {
        var x = 42;
        var y = x / (x - x); // will throw a DivideByZeroException

        // IMPORTANT NOTE: the error in following string format IS intentional
        // and exists to throw an exception to the FormatException catch, below
        Console.WriteLine("The secret to life, the universe, and everything is {1}", y); 
    }
    catch (DivideByZeroException)
    {
        // we do not need a reference to the exception
        Console.WriteLine("Dividing by zero would destroy the universe.");

        // do this to preserve the stack trace:
        throw;
    }
    catch (FormatException ex)
    {
        // only do this if you need to change the type of the Exception to be thrown 
        // and wrap the inner Exception

        // remember that the stack trace of the outer Exception will point to the
        // next line

        // you'll need to examine the InnerException property to get the stack trace
        // to the line that actually started the problem

        throw new InvalidOperationException("Watch your format string indexes.", ex);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);

        // do not do this, because the stack trace will be changed to point to
        // this location instead of the location where the exception
        // was originally thrown:
        throw ex; 
    }
}

static void Main()
{
    try
    {
        AskTheUltimateQuestion();
    }
    catch
    {
        // choose this kind of catch if you don't need any information about 
        // the exception that was caught

        // this block "eats" all exceptions instead of rethrowing them
    }
}

È possibile filtrare per tipo di eccezione e anche per proprietà di eccezione (nuovo in C # 6.0, un po 'più lungo disponibile in VB.NET (citazione necessaria)):

Documentazione / C # / nuove funzionalità

Filtri di eccezione

Poiché le eccezioni C # 6.0 possono essere filtrate usando l'operatore when .

Questo è simile all'utilizzo di un semplice if non si srotola lo stack se la condizione all'interno di when non è soddisfatta.

Esempio

try
{ 
  // ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
  // ...
}

Le stesse informazioni si possono trovare nelle Funzionalità C # 6.0 qui: Filtri di eccezione

Ripartire un'eccezione all'interno di un blocco catch

All'interno di un blocco catch , la parola chiave throw può essere utilizzata da sola, senza specificare un valore di eccezione, per ripensare all'eccezione appena rilevata. Il richiamo di un'eccezione consente all'eccezione originale di continuare la catena di gestione delle eccezioni, preservando lo stack di chiamata oi dati associati:

try {...}
catch (Exception ex) {
  // Note: the ex variable is *not* used
  throw;
}

Un anti-pattern comune è invece quello di throw ex , che ha l'effetto di limitare la vista del prossimo gestore di eccezioni della traccia dello stack:

try {...}
catch (Exception ex) {
  // Note: the ex variable is thrown
  //  future stack traces of the exception will not see prior calls
  throw ex;  
}

In generale, utilizzando throw ex non è auspicabile, come i futuri gestori di eccezioni, che ispezionano l'analisi dello stack saranno in grado di vedere le chiamate fin dal throw ex . Omettendo la variabile ex e usando solo la parola chiave throw l'eccezione originale sarà "bubble-up" .

Lanciare un'eccezione da un metodo diverso preservando le sue informazioni

Occasionalmente potresti catturare un'eccezione e lanciarla da un thread o metodo diverso preservando lo stack delle eccezioni originale. Questo può essere fatto con ExceptionDispatchInfo :

using System.Runtime.ExceptionServices;

void Main()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        throw new Exception();
    }
    catch (Exception ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }
    
    Foo(capturedException);
}

void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
    // Do stuff

    if (capturedException != null)
    {
        // Exception stack trace will show it was thrown from Main() and not from Foo()
        exceptionDispatchInfo.Throw();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow