Exception Handling in c#-: Exception handling allows programmers to deal with unexpected situations that may occur in programs.As an example, consider opening a file using the StreamReader class in the System.IO namespace. To see what kinds of exceptions this class may throw, we can hover the cursor over the class name in Visual Studio. For instance, we may see the System.IO exceptions FileNotFoundException and DirectoryNotFoundException. If any of those exceptions occurs, the program will terminate with an error message.
using System;
using System.IO;
class ErrorHandling
{
static void Main()
{
// Run-time error
StreamReader sr = new StreamReader(“missing.txt”);
}
}
Try-Catch Statement-: To avoid crashing the program the exceptions must be caught using a try-catch statement. This statement consists of a try block containing the code that may cause the exception, and one or more catch clauses. If the try block successfully executes, the program will then continue running after the try-catch statement. However, if an exception occurs, the execution will then be passed to the first catch block able to handle that exception type.
try
{
StreamReader sr = new StreamReader(“missing.txt”);
}
catch
{
Console.WriteLine(“File not found”);
}
Catch Block-: Since the previous catch block is not set to handle any specific exception, it will catch all of them. This is equivalent to catching the System.Exception class, because all exceptions derive from this class.
catch (Exception) {}
To catch a more specific exception, that catch block needs to be placed before more general exceptions.
catch (FileNotFoundException) {}
catch (Exception) {}
The catch block can optionally define an exception object that can be used to obtain more information about the exception, such as a description of the error.
catch (Exception e)
{
Console.WriteLine(“Error: ” + e.Message);
}
Exception Filters-: Exception filters were added in C# 6 and allow catch blocks to include conditions. The condition is appended to the catch block using the when keyword. A matched exception will then only be caught if the condition evaluates to true, as in the following example.
try
{
StreamReader sr = new StreamReader(“missing.txt”);
}
catch (FileNotFoundException e)
when (e.FileName.Contains(“.txt”))
{
Console.WriteLine(“Missing text file: ” + e.FileName);
}
When using exception filters the same exception type may appear in multiple catch clauses. Additionally, there are scenarios when a more general exception can be placed before more specific ones. In the next example, all exceptions are logged by calling a logging method as an exception filter. Because the method returns false, the general exception is not caught and thereby allows for another catch block to handle the exception.
using System;
using System.IO;
static class ErrorHandling
{
// Extension method
public static bool LogException(this Exception e)
{
Console.Error.WriteLine($”Exception: {e}”);
return false;
}
static void Main()
{
try
{
var sr = new StreamReader(“missing.txt”);
}
catch (Exception e) when (LogException(e))
{
// Never reached
}
catch (FileNotFoundException)
{
// Actual handling of exception
}
}
}
Note the use of the var keyword here, which lets the compiler determine the type of a local variable based on the assignment. In this condition when the type of the variable is obvious from the assignment, var can be used to shorten the code and arguably improve readability. When we are not sure what type a variable is, we can hover the mouse cursor over it in the IDE to display the type. Keep in mind that var can only be used when a local variable is both declared and initialized at the same time.
Finally Block-: As the last clause in the try-catch statement, a finally block can be added. This block is used to clean up certain resources allocated in the try block. In limited system resources and graphical components need to be released in this way once they are no longer needed. The code in the finally block will always execute, whether or not there is an exception. This will be the case even if the try block ends with a jump statement, such as return.
In the last example we used the file opened in the try block should be closed if it was successfully opened. This is done properly in the next code segment. To be able to access the StreamReader object from the finally clause, it must be declared outside of the try block. Keep in mind that if we forget to close the stream, the garbage handler will eventually close it for us, but it is good practice to do it our self.
The previous statement is known as a try-catch-finally statement. The catch block may also be left out to create a try-finally statement. This statement will not catch any exceptions. Instead, it will ensure the proper disposal of any resources allocated in the try block. This can be useful if the allocated resource does not throw any exceptions. For instance, such a class would be Bitmap, in the System.Drawing namespace
when using a Console Project a reference to the System.Drawing assembly needs to be manually added for those members to be accessible. To do so, right-click the References folder in the Solution Explorer window and select Add Reference.
The using Statement-: The using statement provides a simpler syntax for writing the try-finally statement. This statement starts with the using keyword followed by the resource to be acquired, specified in parentheses. It then includes a code block in which the obtained resource can be used. When the code block finishes executing, the Dispose method of the object is automatically called to clean it up. This method comes from the System.IDisposable interface, so the specified resource must implement this interface. The following code performs the same function as the one in the previous example, but with fewer lines of code.
using System.Drawing;
// …
using (Bitmap b = new Bitmap(100, 100))
{
System.Console.WriteLine(“Width: ” + b.Width + “,
Height: ” + b.Height);
}
Throwing Exceptions-: When a situation occurs that a method cannot recover from, it can generate an exception to signal the caller that the method has failed. This is done using the throw keyword followed by a new instance of a class deriving from System.Exception.
static void MakeError()
{
throw new System.DivideByZeroException(“My Error”);
}
The exception will then propagate up the caller stack until it is caught. If a caller catches the exception but is not able to recover from it, the exception can be re-thrown using only the throw keyword. If there are no more try-catch statements, the program will stop executing and display the error message.