EXCEPTIONS IN C SHARP
Until now, in our programs we have assumed that the execution was carried out without errors. However, regardless of the skill of the code writer, error situations can occur simply because the reasons for this are not always predictable or manageable: a method can raise an error due to a developer oversight, but also in response. a hardware problem or attempting to access an unavailable resource. Now let’s see the mechanism that .NET 8 makes available to limit the errors that can occur. To analyze the exceptions in c sharp we start with a small program that performs the division between two numbers.
using System; namespace Eccezioni { class Program { static void Main(string[] args) { Console.Write("Enter the Dividend:"); string dividendo = Console.ReadLine(); Console.Write("Enter the divider:"); string divisore = Console.ReadLine(); int num1 = Convert.ToInt32(dividendo); int num2 = Convert.ToInt32(divisore); int result = Divisione(num1,num2); Console.WriteLine(result); } static int Divisione(int a, int b) { return a/b; } } }
What happens if the user passes zero as a divider? What if instead of passing a number it passes a string? In both situations, an unhandled exception occurs, this means that the program terminates at the point where the error occurs and displays an error message in the console.
THE TRY CATCH BLOCKS
As you can see from the figure, the code ends without being handled Unhandled exception and the exception raised is of type System.DivideByZeroException. To manage this situation, we use a try block with which we tell the compiler that the following instructions could generate an exception, if the exception does not occur, the program flow continues normally. The catch block takes care of managing any error condition. Let’s see a code example.
using System; namespace Eccezioni { class Program { static void Main(string[] args) { Console.Write("Enter the Dividend:"); string dividendo = Console.ReadLine(); Console.Write("Enter the divider:"); string divisore = Console.ReadLine(); int num1 = Convert.ToInt32(dividendo); int num2 = Convert.ToInt32(divisore); int result = Divisione(num1,num2); Console.WriteLine(result); } static int Divisione(int a, int b) { try { return a/b; } catch(DivideByZeroException e) { Console.WriteLine($"You entered zero as a divisor, exception thrown {e.Message}"); return 0; } catch(Exception e) { Console.WriteLine($"This exception occurred: {e.Message}"); return 0; } } } }
THE SYSTEM.EXCEPTION CLASS
As you can see, you can insert multiple catch blocks. .NET 8 is a technology completely oriented towards object-oriented programming and exploits this paradigm also to represent the errors that are raised at Runtime. We mentioned that, upon the occurrence of an exception, the CLR associates an instance of a particular object whose type is (or derives from) Exception to the execution context. Precisely the type used is the first discriminant that we can use to determine the nature of the exception that has occurred, as we could verify in the example a division by zero in fact raises a DivisionByZeroException, while instead, accessing a non-existent file for reading, throws an error represented by the FileNotFoundException type.
HIERARCHY OF EXCEPTIONS
The Exception class in particular, is the progenitor of a numerous hierarchy of types, each of which is associated with a particular case of error. The Exception class represents a more generic exception, for this reason, if we want to specify more catch blocks, the more generic exception classes must be inserted first and the Exception class at the bottom. Obviously putting Exception before more specific exceptions these would never be executed.
EXCEPTIONS IN C SHARP RELAUNCH AN EXCEPTION THE THROW CLAUSE
Sometimes in a hierarchy of operations between methods it can be useful, after catching the exception, to throw it back to callers using the throw keyword for example in the code I showed you instead of handling the division by zero error in the method we could do it in the Main by creating a centralized manager that takes care of the division by zero and a possible entry of a non-numeric value that would lead to a new exception.
using System; namespace Eccezioni { class Program { static void Main(string[] args) { int result = 0; Console.Write("Enter the Dividend:"); string dividendo = Console.ReadLine(); Console.Write("Enter the divider:"); string divisore = Console.ReadLine(); try { int num1 = Convert.ToInt32(dividendo); int num2 = Convert.ToInt32(divisore); result = Divisione(num1,num2); } catch(DivideByZeroException e) { Console.WriteLine($"You entered zero as a divisor, exception thrown {e.Message}"); } catch(InvalidCastException e) { Console.WriteLine($"You have entered invalid values exception thrown {e.Message}"); } catch(Exception e) { Console.WriteLine($"This exception occurred: {e.Message}"); } Console.WriteLine(result); } static int Divisione(int a, int b) { try { return a/b; } catch(Exception ex) { throw new DivideByZeroException("Division by zero",ex); } } } }
THE FINALLY BLOCK
Sometimes the need we have is not to intercept a particular type of exception, but to make sure that a certain portion of code is executed anyway, both in the presence and absence of an error. Typically this is code called cleanup, ie used to free up resources. For example, think of a file that has been opened for reading, or a connection to a database. In such cases it is necessary to free up the used resources as soon as possible, and this can be done in a finally block.
using System; namespace Eccezioni { class Program { static void Main(string[] args) { int result = 0; Console.Write("Enter the Dividend:"); string dividendo = Console.ReadLine(); Console.Write("Enter the divider:"); string divisore = Console.ReadLine(); try { int num1 = Convert.ToInt32(dividendo); int num2 = Convert.ToInt32(divisore); result = Divisione(num1,num2); } catch(DivideByZeroException e) { Console.WriteLine($"You entered zero as a divisor, exception thrown {e.Message}"); } catch(InvalidCastException e) { Console.WriteLine($"You have entered invalid values exception thrown {e.Message}"); } catch(Exception e) { Console.WriteLine($"This exception occurred: {e.Message}"); } finally { Console.WriteLine(result); } } static int Divisione(int a, int b) { try { return a/b; } catch(Exception ex) { if(b==0) throw new DivideByZeroException("Division by zero.",ex); else throw new Exception("A generic exception occurred.",ex); } } } }
IN-DEPTH STUDY
In C#, exceptions are mechanisms for handling errors and abnormal conditions that may occur during the execution of a program. Using exceptions, you can separate code that handles errors from code that performs normal operations. Here is an overview of how exceptions work in C# and how to use them.
Basic structure of exceptions
In C#, exceptions are handled using the try, catch, finally, and throw blocks.
– try: Contains code that can generate an exception.
– catch: Blocks exceptions raised in the try block and specifies how to handle them.
– finally: Contains code that is executed regardless of whether an exception has occurred or not.
– throw: Used to raise an exception.
Basic Example.
try
{
// Codice che potrebbe generare un’eccezione
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // Questo causerà un’eccezione
}
catch (IndexOutOfRangeException ex)
{
// Gestisce l’eccezione
Console.WriteLine(“Errore: Indice fuori dai limiti dell’array.“);
Console.WriteLine(ex.Message);
}
finally
{
// Codice che viene eseguito comunque
Console.WriteLine(“Blocco finally sempre eseguito.“);
}
Common types of exceptions
Some of the common exception types in C# include:
– System.Exception: The base class for all exceptions.
– System.ArgumentException: Raised when an argument is invalid.
– System.ArgumentNullException: Raised when a null argument is invalid.
– System.InvalidOperationException: Raised when an operation is invalid for the current state of the object.
– System.NullReferenceException: Raised when an attempt is made to dereference a null object.
– System.IndexOutOfRangeException: Raised when attempting to access an array element with an out-of-bounds index.
Raise Exceptions.
Custom exceptions can be raised using the throw keyword.
public void VerificaEtà(int età)
{
if (età < 0)
{
throw new ArgumentOutOfRangeException(nameof(età), “L’età non può essere negativa.“);
}
// Codice per gestire età valide
}
Create custom exceptions
To create your own exception, you can inherit from the System.Exception class.
public class MiaEccezionePersonalizzata : Exception
{
public MiaEccezionePersonalizzata() { }
public MiaEccezionePersonalizzata(string message)
: base(message) { }
public MiaEccezionePersonalizzata(string message, Exception inner)
: base(message, inner) { }
}
Using custom exceptions
try
{
// Codice che potrebbe sollevare una MiaEccezionePersonalizzata
}
catch (MiaEccezionePersonalizzata ex)
{
Console.WriteLine($”Errore personalizzato: {ex.Message}”);
}
Best Practices.
1. Handle only those exceptions that you can handle: Don’t catch exceptions that you don’t know how to handle.
2. Use specific exceptions: Catch specific exceptions instead of using catch (Exception ex).
3. Do not abuse exceptions: Exceptions should be used for exceptional conditions and not for normal control flow.
4. Log exceptions: Log exceptions to facilitate debugging and software maintenance.
Properly handling exceptions improves code robustness and maintainability.
Leave A Comment