When should an exception be thrown

When an action member of a type cannot complete the action task, an exception should be thrown to notify the caller.

An action member is an operation that the type itself or an instance of the type can perform, such as Append, Insert, etc., as defined in C# StringBuilder

Catch the exception code structure
Private void DoSomething () {try {/ / may be abnormal code here} the catch (InvalidOperationException) { / / capture InvalidOperationException is unusual, the corresponding processing code here} the catch (IOException) {/ / capture IOException exception, } catch (Exception) {// throw the Exception () {// throw the Exception (); } finally {// This code is always executed} // If the try block does not throw an exception or a catch catches an exception but does not throw it, execute the following code; otherwise, the following code does not execute}
Try block

The try block contains code that can cause an exception to occur. The exception recovery code should be placed in one or more catch blocks. An application-safe recovery of an exception requires a corresponding catch block. A try block must be associated with at least one catch block or finally block. A single try block is not allowed in C# and would be meaningless.

* If a try block contains multiple operations that may throw the same type of exception, but each operation has different recovery actions, we should split those operations into its own try block to ensure the correct recovery state

Catch block

A catch block contains the code that needs to be executed in response to an exception. A try block can be associated with zero or more catch blocks. If no exception occurs in the code in the try block, the CLR will never execute the code in the catch block. The thread will skip all catch blocks up to the code in the finally block (if there is code in it). The expression in parentheses following the catch keyword is called the catch type, which is the type of exception to catch.

* When debugging a catch block with Visual Studio, you can add a special variable name $Exception to the monitor window to check the object that is currently throwing an exception

Catch block retrieval order and considerations

The CLR retrieves a matching catch block from the top down, so program with the most derived Exception types at the top, followed by their base classes, and finally System.Exception. If the order is not correct, such as placing the most specific Exception types in the bottom catch block, the CLR will retrieve a matching catch block from the top down. The C# compiler will cause an error because the catch block cannot be executed.

If an exception occurs in the try block and there is no matching catch block, the CLR calls a higher level of the stack to search for the matching exception type, and if it is not found at the top of the stack, an unhandled exception occurs.

Something that can be done at the end of a catch block
  • Rethrow the same exception, notifying the code one level higher in the call stack that the exception has occurred
  • Throw a different exception, providing richer exception information to the code higher up the call stack
  • Let the thread exit from the bottom of the catch block

In the first two techniques, the CLR goes back through the call stack, looks for a catch block whose catch type matches the type that threw the exception, and throws an exception. If you choose to exit the thread from the bottom of the catch block, the code contained in the finally block is executed immediately, and the statement immediately following the finally block is executed. If there is no finally block, the thread will start execution from the statement after the last catch block.

Finally block

The code in the finally block is the code that is guaranteed to execute and must follow any catch block, usually containing the resource cleanup operation required for the action in the try block. A try block can be associated with at most one finally block.

private void ReadFile(string path) { FileStream fs = null; try { fs = new FileStream(path, FileMode.Open); // Processing file data... } catch (ioException) {// ioException recovery code} finally {// make sure the file is closed if (fs! = null) fs.Close(); }}

The file must be closed regardless of whether the try block has an exception or not. It is not correct to put the code that closes the file after the finally block statement, because if an exception is thrown and not caught, the statement after the finally block will never be executed until the next garbage collection closes the file.

In general, the catch block and finally block should have only one or two lines of code

Introduction to the properties of the System.Exception class
  • The read-only property Message: String type indicates why the exception was thrown
  • The read-only attribute Data: Idictionary type, to which the code adds a record entry before throwing an exception
  • A readable and writable property of type Source: String containing the name of the assembly that generated the exception
  • A read-only property of type stackTrace: String that contains the names and signatures of all methods that were called before the exception was thrown to help debug the code
  • The read-only property is of type targetSite: MethodBase, which contains the method to throw the exception
  • The read-only attribute, String containing the URL of the exception document, is not recommended
  • Read-only property InnerException: Type Exception, usually NULL, which indicates what the previous Exception was if the current Exception was thrown while an Exception was being handled
Use exception classes correctly
  • Make good use of finally blocks, often used to display freed objects to avoid resource leaks
  • Maintains state and rolls back partially completed operations in the event of an unrecoverable exception
  • Catch an exception in one thread and rethrow it in another
  • Recovering state from an exception properly
private string SomeMothods() { var result = ""; var a = 1; var b = 0; try { a /= b; } catch (divideByZeroException) {result = "no "; } return result; }
Unhandled exception

When an exception is thrown, the CLR looks up the call stack for a catch block that matches the type of the object that threw the exception. If it is not found, an unhandled exception occurs. When the CLR detects that any thread in the process has an unhandled exception, it terminates the process. The occurrence of an unhandled exception indicates that the program has encountered an unexpected situation. At the same time, when an unhandled exception occurs, Windows will write a record to the event log, which can be viewed by opening the event viewer

Abnormal Settings

The exception setting window can be opened through the debug menu as shown in the figure

Expand Common Languages Runtime Exceptions to see the types of Exceptions that Visual Studio recognizes

If the check box for the exception type is checked, the debugger breaks when the exception is thrown, and the CLR does not look for any matching catch block. If the check box for an exception class is unchecked, the debugger will interrupt only if that exception type is not handled.

You can also add custom exception types through the add operation

Performance issues with exception handling
  • Unmanaged C ++ Compiler: The compiler must generate code to keep track of which objects were successfully constructed. The compiler must also generate code to call the destructor of each object that has been successfully constructed when an exception is caught. This creates a large amount of bookkeeping code in the program, which negatively affects the size of the code and the execution time.
  • Managed compiler: Because managed objects are allocated in the managed heap, the managed heap is monitored by garbage collection. If an object is successfully constructed and an exception is thrown, the garbage collector will eventually free the object’s memory. The compiler does not need to generate any bookkeeping code to keep track of successfully constructed objects, nor does it need to guarantee calls to the destructor. Compared to managed C ++, this means less code generated, less code to run, and better application performance.