© Mikael Olsson 2020
M. OlssonC# 8 Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-5577-3_21

21. Exception Handling

Mikael Olsson1 
(1)
HAMMARLAND, Finland
 
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, you can hover the cursor over the class name in Visual Studio. For instance, you 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.0 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 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
    }
  }
}

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. Typically, 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 example used previously, 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 you forget to close the stream, the garbage collector will eventually close it for you, but it is good practice to do it yourself.
StreamReader sr = null;
try {
  sr = new StreamReader("missing.txt");
}
catch (FileNotFoundException) {}
finally {
  if (sr != null) sr.Close();
}
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.
using System.Drawing;
// ...
Bitmap b = null;
try {
  b = new Bitmap(100, 50);
  System.Console.WriteLine(b.Width); // "100"
}
finally {
  if (b != null) b.Dispose();
}

Note that 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. Then from Assemblies ➤ Framework, select the System.Drawing assembly and click OK to add its reference to your project.

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;
// ...
void using (Bitmap b = new Bitmap(100, 50)) {
  System.Console.WriteLine(b.Width); // "100"
} // disposed
C# 8.0 simplified resource management further by allowing for using declarations. This removes the need for the curly brackets as the resource handler will automatically be disposed of when it goes out of scope.
void MyBitmap()
{
  using Bitmap b = new Bitmap(100, 50);
  System.Console.WriteLine(b.Height); // "50"
} // disposed

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 rethrown using only the throw keyword. If there are no more try-catch statements, the program will stop executing and display the error message.
static void Main()
{
  try {
    MakeError();
  }
  catch {
    throw; // rethrow error
  }
}
As a statement, the throw keyword cannot be used in contexts that require an expression, such as inside a ternary statement. C# 7.0 changed this by allowing throw to also be used as an expression. This expands the locations from which exceptions may be thrown, such as inside the following null-coalescing expression.
using System;
class MyClass
{
  private string _name;
  public string name
  {
    get => _name;
    set => _name = value ?? throw new
      ArgumentNullException(nameof(name)+" was null");
  }
  static void Main()
  {
    MyClass c = new MyClass();
    c.name = null; // exception: name was null
  }
}

Note the use of the nameof expression here, which was introduced in C# 6.0. This expression turns the symbol inside the parentheses into a string. The benefit of this shows itself if the property is renamed, as the IDE can then find and rename this symbol. This would not be the case if a string had been used instead.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.87.60