Ricerca…


Gestione delle eccezioni di base

try
{
    /* code that could throw an exception */
}
catch (Exception ex)
{
    /* handle the exception */
}

Si noti che la gestione di tutte le eccezioni con lo stesso codice spesso non è l'approccio migliore.
Questo è comunemente usato quando qualsiasi routine di gestione delle eccezioni interne fallisce, come ultima risorsa.

Gestione di tipi di eccezione specifici

try
{
    /* code to open a file */
}
catch (System.IO.FileNotFoundException)
{
    /* code to handle the file being not found */
}
catch (System.IO.UnauthorizedAccessException)
{
    /* code to handle not being allowed access to the file */
}
catch (System.IO.IOException)
{
    /* code to handle IOException or it's descendant other than the previous two */
}
catch (System.Exception)
{
    /* code to handle other errors */
}

Fai attenzione che le eccezioni siano valutate in ordine e l'ereditarietà sia applicata. Quindi è necessario iniziare con quelli più specifici e terminare con il loro antenato. In qualsiasi punto, verrà eseguito un solo blocco catch.

Utilizzando l'oggetto eccezione

È consentito creare e generare eccezioni nel proprio codice. L'istanziazione di un'eccezione viene eseguita allo stesso modo di qualsiasi altro oggetto C #.

Exception ex = new Exception();

// constructor with an overload that takes a message string
Exception ex = new Exception("Error message"); 

È quindi possibile utilizzare la parola chiave throw per aumentare l'eccezione:

try
{
    throw new Exception("Error");
}
catch (Exception ex)
{
    Console.Write(ex.Message); // Logs 'Error' to the output window
} 

Nota: se stai lanciando una nuova eccezione all'interno di un blocco catch, assicurati che l'eccezione originale sia passata come "eccezione interna", ad es

void DoSomething() 
{
    int b=1; int c=5;
    try
    {
        var a = 1; 
        b = a - 1;
        c = a / b;
        a = a / c;
    }        
    catch (DivideByZeroException dEx) when (b==0)
    {
        // we're throwing the same kind of exception
        throw new DivideByZeroException("Cannot divide by b because it is zero", dEx);
    }
    catch (DivideByZeroException dEx) when (c==0)
    {
        // we're throwing the same kind of exception
        throw new DivideByZeroException("Cannot divide by c because it is zero", dEx);
    }
}

void Main()
{    
    try
    {
        DoSomething();
    }
    catch (Exception ex)
    {
        // Logs full error information (incl. inner exception)
        Console.Write(ex.ToString()); 
    }    
}

In questo caso si presume che l'eccezione non possa essere gestita, ma alcune informazioni utili vengono aggiunte al messaggio (e l'eccezione originale può ancora essere letta tramite ex.InnerException da un blocco di eccezioni esterno).

Mostrerà qualcosa come:

System.DivideByZeroException: Non può dividere per b perché è zero ---> System.DivideByZeroException: Tentativo di divisione per zero.
a UserQuery.g__DoSomething0_0 () in C: [...] \ LINQPadQuery.cs: riga 36
--- Fine della traccia dello stack delle eccezioni interne ---
a UserQuery.g__DoSomething0_0 () in C: [...] \ LINQPadQuery.cs: riga 42
a UserQuery.Main () in C: [...] \ LINQPadQuery.cs: riga 55

Se stai provando questo esempio in LinqPad, noterai che i numeri di riga non sono molto significativi (non sempre ti aiutano). Tuttavia, il passaggio di un testo di errore utile come suggerito sopra spesso riduce significativamente il tempo necessario per rintracciare la posizione dell'errore, che in questo esempio è chiaramente la linea

c = a / b;

in funzione DoSomething() .

Provalo su .NET Fiddle

Finalmente blocco

try
{
    /* code that could throw an exception */
}
catch (Exception)
{
    /* handle the exception */
}
finally
{
    /* Code that will be executed, regardless if an exception was thrown / caught or not */
}

Il blocco try / catch / finally può essere molto utile durante la lettura da file.
Per esempio:

FileStream f = null;

try
{
    f = File.OpenRead("file.txt");
    /* process the file here */
}
finally
{
    f?.Close(); // f may be null, so use the null conditional operator.
}

Un blocco try deve essere seguito da un catch o da un blocco finally . Tuttavia, poiché non esiste un blocco catch, l'esecuzione causerà la chiusura. Prima della conclusione, verranno eseguite le istruzioni all'interno del blocco finally.

Nella lettura dei file avremmo potuto usare un blocco using come FileStream (ciò che OpenRead restituisce) implementa IDisposable .

Anche se c'è una dichiarazione di return nel blocco try , il blocco finally verrà eseguito di solito; ci sono alcuni casi in cui non lo faranno:

Implementazione di IErrorHandler per i servizi WCF

Implementare IErrorHandler per i servizi WCF è un ottimo modo per centralizzare la gestione degli errori e la registrazione. L'implementazione mostrata qui dovrebbe rilevare eventuali eccezioni non gestite generate a seguito di una chiamata a uno dei servizi WCF. Inoltre, in questo esempio viene mostrato come restituire un oggetto personalizzato e come restituire JSON piuttosto che l'XML predefinito.

Implementare IErrorHandler:

using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace BehaviorsAndInspectors
{
    public class ErrorHandler : IErrorHandler
    {

        public bool HandleError(Exception ex)
        {
            // Log exceptions here

            return true;

        } // end

        public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
        {
            // Get the outgoing response portion of the current context
            var response = WebOperationContext.Current.OutgoingResponse;

            // Set the default http status code 
            response.StatusCode = HttpStatusCode.InternalServerError;

            // Add ContentType header that specifies we are using JSON
            response.ContentType = new MediaTypeHeaderValue("application/json").ToString();

            // Create the fault message that is returned (note the ref parameter) with BaseDataResponseContract                
            fault = Message.CreateMessage(
                version,
                string.Empty,
                new CustomReturnType { ErrorMessage = "An unhandled exception occurred!" },
                new DataContractJsonSerializer(typeof(BaseDataResponseContract), new List<Type> { typeof(BaseDataResponseContract) }));

            if (ex.GetType() == typeof(VariousExceptionTypes))
            {
                 // You might want to catch different types of exceptions here and process them differently
            }

            // Tell WCF to use JSON encoding rather than default XML
            var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty);

        } // end

    } // end class

} // end namespace

In questo esempio colleghiamo il gestore al comportamento del servizio. È inoltre possibile allegare ciò a IEndpointBehavior, IContractBehavior o IOperationBehavior in modo simile.

Allegare ai comportamenti di servizio:

using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace BehaviorsAndInspectors
{
    public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
    {
        public override Type BehaviorType
        {
            get { return GetType(); }
        }

        protected override object CreateBehavior()
        {
            return this;
        }

        private IErrorHandler GetInstance()
        {
            return new ErrorHandler();
        }

        void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end

        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            var errorHandlerInstance = GetInstance();

            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(errorHandlerInstance);
            }
        }

        void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end
      
    } // end class

} // end namespace

Config in Web.config:

...
<system.serviceModel>

    <services>      
      <service name="WebServices.MyService">
        <endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
      </service>
    </services>

    <extensions>      
      <behaviorExtensions>        
        <!-- This extension if for the WCF Error Handling-->
        <add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />      
      </behaviorExtensions>    
    </extensions>

    <behaviors>          
      <serviceBehaviors>        
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <ErrorHandlerBehavior />
        </behavior>     
      </serviceBehaviors>    
    </behaviors>

    ....
</system.serviceModel>
...

Ecco alcuni link che potrebbero essere utili su questo argomento:

https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx

http://www.brainthud.com/cards/5218/25441/which-four-behavior-interfaces-exist-for-interacting-with-a-service-or-client-description-what-methods-do-they- attuare e

Altri esempi:

IErrorHandler che restituisce un corpo di messaggio errato quando il codice di stato HTTP è 401 Non autorizzato

IErrorHandler non sembra gestire i miei errori in WCF ... qualche idea?

Come rendere il gestore degli errori WCF personalizzato restituire la risposta JSON con codice http non OK?

Come si imposta l'intestazione Content-Type per una richiesta HttpClient?

Creazione di eccezioni personalizzate

È consentito implementare eccezioni personalizzate che possono essere generate come qualsiasi altra eccezione. Questo ha senso quando vuoi rendere le tue eccezioni distinguibili da altri errori durante il runtime.

In questo esempio creeremo un'eccezione personalizzata per la gestione chiara dei problemi che l'applicazione potrebbe avere durante l'analisi di un input complesso.

Creazione di classi di eccezioni personalizzate

Per creare un'eccezione personalizzata, crea una sottoclasse di Exception :

public class ParserException : Exception
{
    public ParserException() : 
      base("The parsing went wrong and we have no additional information.") { }
}

L'eccezione personalizzata diventa molto utile quando si desidera fornire informazioni aggiuntive al catcher:

public class ParserException : Exception
{
    public ParserException(string fileName, int lineNumber) : 
      base($"Parser error in {fileName}:{lineNumber}") 
    {
      FileName = fileName;
      LineNumber = lineNumber;
    }
    public string FileName {get; private set;}
    public int LineNumber {get; private set;}    
}

Ora, quando si catch(ParserException x) si avrà semantica aggiuntiva per ottimizzare la gestione delle eccezioni.

Le classi personalizzate possono implementare le seguenti funzionalità per supportare scenari aggiuntivi.

ri-lancio

Durante il processo di analisi, l'eccezione originale è ancora interessante. In questo esempio è un FormatException perché il codice tenta di analizzare un pezzo di stringa, che dovrebbe essere un numero. In questo caso l'eccezione personalizzata dovrebbe supportare l'inclusione di " InnerException ":

//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}

serializzazione

In alcuni casi le eccezioni potrebbero dover attraversare i confini di AppDomain. Questo è il caso se il parser è in esecuzione nel proprio AppDomain per supportare il ricaricamento delle nuove configurazioni del parser. In Visual Studio, è possibile utilizzare il modello di Exception per generare codice come questo.

[Serializable]
public class ParserException : Exception
{
    // Constructor without arguments allows throwing your exception without
    // providing any information, including error message. Should be included
    // if your exception is meaningful without any additional details. Should
    // set message by calling base constructor (default message is not helpful).
    public ParserException()
        : base("Parser failure.")
    {}

    // Constructor with message argument allows overriding default error message.
    // Should be included if users can provide more helpful messages than
    // generic automatically generated messages.
    public ParserException(string message) 
        : base(message)
    {}

    // Constructor for serialization support. If your exception contains custom
    // properties, read their values here.
    protected ParserException(SerializationInfo info, StreamingContext context) 
        : base(info, context)
    {}
}

Utilizzo di ParserException

try
{
    Process.StartRun(fileName)
}
catch (ParserException ex)
{
    Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x) 
{
    ...
}

È inoltre possibile utilizzare eccezioni personalizzate per l'acquisizione e il wrapping delle eccezioni. In questo modo molti errori diversi possono essere convertiti in un singolo tipo di errore che è più utile all'applicazione:

try
{
    int foo = int.Parse(token);
}
catch (FormatException ex)
{
    //Assuming you added this constructor
    throw new ParserException(
      $"Failed to read {token} as number.", 
      FileName, 
      LineNumber, 
      ex);
}

Quando si gestiscono eccezioni aumentando le proprie eccezioni personalizzate, si dovrebbe in genere includere un riferimento all'eccezione originale nella proprietà InnerException , come mostrato sopra.

Problemi di sicurezza

Se esporre il motivo dell'eccezione potrebbe compromettere la sicurezza consentendo agli utenti di vedere il funzionamento interno dell'applicazione, può essere una cattiva idea avvolgere l'eccezione interna. Questo potrebbe essere applicato se stai creando una libreria di classi che verrà utilizzata da altri.

Ecco come puoi generare un'eccezione personalizzata senza avvolgere l'eccezione interna:

try
{
  // ...
}
catch (SomeStandardException ex)
{
  // ...
  throw new MyCustomException(someMessage);
}

Conclusione

Quando si genera un'eccezione personalizzata (con wrapping o con una nuova eccezione unwrapped), è necessario generare un'eccezione significativa per il chiamante. Ad esempio, un utente di una libreria di classi potrebbe non sapere molto su come quella libreria faccia il suo lavoro interno. Le eccezioni generate dalle dipendenze della libreria di classi non sono significative. Piuttosto, l'utente desidera un'eccezione pertinente al modo in cui la libreria di classi utilizza tali dipendenze in modo errato.

try
{
  // ...
}
catch (IOException ex)
{
  // ...
  throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details. 
If you are not able to resolve the problem, please call 555-555-1234 for technical       
assistance.", ex);
}

Eccezione anti-modelli

Ingerire le eccezioni

Si dovrebbe sempre ripetere l'eccezione nel seguente modo:

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw;
}

Rilanciare un'eccezione come quella di seguito offusca l'eccezione originale e perderà la traccia dello stack originale. Non si dovrebbe mai farlo! La traccia dello stack prima del fermo e del rethrow andrà persa.

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw ex;
}

Baseball Exception Handling

Non si dovrebbero usare le eccezioni come sostituto dei normali costrutti di controllo del flusso come le istruzioni if-then e i cicli while. Questo anti-pattern è talvolta chiamato Baseball Exception Handling .

Ecco un esempio di anti-pattern:

try
{
    while (AccountManager.HasMoreAccounts())
    {
        account = AccountManager.GetNextAccount();
        if (account.Name == userName)
        {
            //We found it
            throw new AccountFoundException(account);
        }
    }
}
catch (AccountFoundException found)
{
    Console.Write("Here are your account details: " + found.Account.Details.ToString());
}

Ecco un modo migliore per farlo:

Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
    account = AccountManager.GetNextAccount();
    if (account.Name == userName)
    {
        //We found it
        found = account;
    }
}
Console.Write("Here are your account details: " + found.Details.ToString());

cattura (eccezione)

Ci sono quasi no (alcuni dicono nessuno!) Ragioni per catturare il tipo di eccezione generico nel codice. Dovresti prendere solo i tipi di eccezioni che ti aspetti di accadere, perché altrimenti nascondi bug nel tuo codice.

try 
{
     var f = File.Open(myfile);
     // do something
}
catch (Exception x)
{
     // Assume file not found
     Console.Write("Could not open file");
     // but maybe the error was a NullReferenceException because of a bug in the file handling code?
}

Meglio fare:

try 
{
     var f = File.Open(myfile);
     // do something which should normally not throw exceptions
}
catch (IOException)
{
     Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException) 
{
     Console.Write("Insufficient rights");
}

Se si verificano altre eccezioni, facciamo intenzionalmente in modo che l'applicazione si blocchi, quindi entra direttamente nel debugger e possiamo risolvere il problema. Non dobbiamo spedire un programma in cui siano presenti altre eccezioni che non avvengano comunque, quindi non è un problema avere un crash.

Anche il seguente è un cattivo esempio, poiché utilizza eccezioni per aggirare un errore di programmazione. Non è quello per cui sono progettati.

public void DoSomething(String s)
{
     if (s == null)
         throw new ArgumentNullException(nameof(s));
     // Implementation goes here
}

try 
{    
     DoSomething(myString);
}
catch(ArgumentNullException x)
{
    // if this happens, we have a programming error and we should check
    // why myString was null in the first place.
}

Eccezioni aggregate / più eccezioni da un metodo

Chi dice che non puoi lanciare più eccezioni con un solo metodo. Se non sei abituato a giocare con AggregateExceptions potresti essere tentato di creare la tua struttura dati per rappresentare molte cose che vanno storte. Ovviamente ci sono altre strutture dati che non sono un'eccezione, ma sono ideali come i risultati di una convalida. Anche se giochi con AggregateExceptions potresti essere dal lato ricevente e gestirli sempre senza rendertene conto che possono esserti utili.

È abbastanza plausibile che un metodo venga eseguito e anche se sarà un fallimento nel suo insieme, vorrai evidenziare più cose che sono andate storte nelle eccezioni generate. Ad esempio, questo comportamento può essere visto con il modo in cui i metodi paralleli funzionano come un'attività suddivisa in più thread e qualsiasi numero di essi potrebbe generare eccezioni e questo deve essere segnalato. Ecco un esempio sciocco di come potresti trarne beneficio:

    public void Run()
    {
        try
        {
            this.SillyMethod(1, 2);
        }
        catch (AggregateException ex)
        {
            Console.WriteLine(ex.Message);
            foreach (Exception innerException in ex.InnerExceptions)
            {
                Console.WriteLine(innerException.Message);
            }
        }
    }

    private void SillyMethod(int input1, int input2)
    {
        var exceptions = new List<Exception>();

        if (input1 == 1)
        {
            exceptions.Add(new ArgumentException("I do not like ones"));
        }
        if (input2 == 2)
        {
            exceptions.Add(new ArgumentException("I do not like twos"));
        }
        if (exceptions.Any())
        {
            throw new AggregateException("Funny stuff happended during execution", exceptions);
        }
    }

Annidamento di eccezioni e prova a catturare blocchi.

Uno è in grado di annidare un'eccezione / try blocco catch nell'altro.

In questo modo è possibile gestire piccoli blocchi di codice che sono in grado di funzionare senza interrompere l'intero meccanismo.

try 
{
//some code here
    try 
    {
        //some thing which throws an exception. For Eg : divide by 0
    }
    catch (DivideByZeroException dzEx)
    {
        //handle here only this exception
        //throw from here will be passed on to the parent catch block
    }
    finally
    {
        //any thing to do after it is done.
    }
 //resume from here & proceed as normal; 
}
catch(Exception e)
{
    //handle here
}

Nota: evitare di ingerire le eccezioni quando si lancia sul blocco catch genitore

Migliori pratiche

Cheatsheet

FARE NON
Controllo del flusso con istruzioni di controllo Controlla il flusso con le eccezioni
Tieni traccia dell'eccezione ignorata (assorbita) mediante la registrazione Ignora eccezione
Ripeti l'eccezione usando il throw Rilanciare l'eccezione - throw new ArgumentNullException() o throw ex
Lancia eccezioni predefinite di sistema Lancia eccezioni personalizzate simili alle eccezioni di sistema predefinite
Getta eccezioni personalizzate / predefinite se è fondamentale per la logica dell'applicazione Getta eccezioni personalizzate / predefinite per indicare un avviso nel flusso
Individua le eccezioni che desideri gestire Cattura ogni eccezione

NON gestire la logica aziendale con eccezioni.

Il controllo del flusso NON dovrebbe essere fatto da eccezioni. Utilizzare invece istruzioni condizionali. Se è possibile eseguire un controllo con l'istruzione if-else chiaro, non utilizzare eccezioni perché riduce la leggibilità e le prestazioni.

Considera il seguente frammento di Mr. Bad Practices:

// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
    Console.WriteLine(myObject.ToString());
}

Quando l'esecuzione raggiunge Console.WriteLine(myObject.ToString()); l'applicazione genererà una NullReferenceException. Mr. Bad Practices ha capito che myObject è nullo e ha modificato il suo snippet per catturare e gestire NullReferenceException :

// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
    try
    {
        Console.WriteLine(myObject.ToString());
    }
    catch(NullReferenceException ex)
    {
        // Hmmm, if I create a new instance of object and assign it to myObject:
        myObject = new object();
        // Nice, now I can continue to work with myObject
        DoSomethingElseWithMyObject();
    }
}

Poiché lo snippet precedente riguarda solo la logica dell'eccezione, cosa devo fare se myObject non è nullo a questo punto? Dove dovrei coprire questa parte della logica? Subito dopo Console.WriteLine(myObject.ToString()); ? Che ne dici dopo il try...catch bloccare il blocco?

Che ne dici di Mr. Best Practices? Come avrebbe gestito questo?

// This is a snippet example for DO
object myObject;
void DoingSomethingWithMyObject()
{
    if(myObject == null)
        myObject = new object();
    
    // When execution reaches this point, we are sure that myObject is not null
    DoSomethingElseWithMyObject();
}

Mr. Best Practices ha ottenuto la stessa logica con meno codice e una logica chiara e comprensibile.

NON ripetere le eccezioni

Rilanciare le eccezioni è costoso. Ha un impatto negativo sulle prestazioni. Per il codice che fallisce regolarmente, è possibile utilizzare modelli di progettazione per ridurre al minimo i problemi di prestazioni. Questo argomento descrive due schemi di progettazione utili quando le eccezioni possono influire in modo significativo sulle prestazioni.

NON assorbire le eccezioni senza registrazione

try
{
    //Some code that might throw an exception
}
catch(Exception ex)
{
    //empty catch block, bad practice
}

Non ingoiare mai le eccezioni. Ignorare le eccezioni salverà quel momento ma creerà un caos per la manutenibilità in seguito. Quando si registrano le eccezioni, è necessario registrare sempre l'istanza dell'eccezione in modo che venga registrata la traccia dello stack completa e non solo il messaggio di eccezione.

try
{
    //Some code that might throw an exception
}
catch(NullException ex)
{
    LogManager.Log(ex.ToString());
}

Non prendere le eccezioni che non puoi gestire

Molte risorse, come questa , ti esortano fortemente a considerare il motivo per cui stai rilevando un'eccezione nel luogo in cui la stai catturando. Dovresti solo prendere un'eccezione se puoi gestirla in quella posizione. Se si può fare qualcosa per mitigare il problema, come provare un algoritmo alternativo, connettersi a un database di backup, provare un altro nome file, attendere 30 secondi e riprovare, o notificare un amministratore, è possibile rilevare l'errore e farlo. Se non c'è nulla che puoi plausibilmente e ragionevolmente fare, semplicemente "lascia andare" e lascia che l'eccezione sia gestita ad un livello più alto. Se l'eccezione è sufficientemente catastrofica e non vi è alcuna opzione ragionevole se non che l'intero programma si arresti in modo anomalo a causa della gravità del problema, allora lascialo andare in crash.

try
{
    //Try to save the data to the main database.
}
catch(SqlException ex)
{
    //Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the exception bubble up to a level where it can be handled.

Eccezione non gestita e thread

AppDomain.UnhandledException Questo evento fornisce la notifica delle eccezioni non rilevate. Consente all'applicazione di registrare le informazioni sull'eccezione prima che il gestore predefinito del sistema segnali l'eccezione all'utente e interrompa l'applicazione. Se sono disponibili informazioni sufficienti sullo stato dell'applicazione, altre le azioni possono essere intraprese, ad esempio il salvataggio dei dati del programma per il successivo recupero. Si consiglia di procedere, poiché i dati del programma possono essere danneggiati quando le eccezioni non vengono gestite.

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    private static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);            
    }

Application.ThreadException Questo evento consente all'applicazione Windows Form di gestire eccezioni altrimenti non gestite che si verificano nei thread di Windows Form. Allegare i gestori di eventi all'evento ThreadException per gestire queste eccezioni, che lasceranno l'applicazione in uno stato sconosciuto. Ove possibile, le eccezioni dovrebbero essere gestite da un blocco strutturato di gestione delle eccezioni.

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    private static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
        Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);
    }

E infine la gestione delle eccezioni

static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Exception ex = (Exception)e.ExceptionObject;
        // your code
    }

static void ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        Exception ex = e.Exception;
        // your code
    }

Lanciare un'eccezione

Il tuo codice può, e spesso dovrebbe, generare un'eccezione quando qualcosa di insolito è successo.

public void WalkInto(Destination destination)
{
    if (destination.Name == "Mordor")
    {
        throw new InvalidOperationException("One does not simply walk into Mordor.");
    }
    // ... Implement your normal walking code here.
}


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