C # basic knowledge sorting Series 10: Exception Handling System. Exception

Source: Internet
Author: User
Tags finally block
Abstract

People are not sages. Code is written by humans, and of course it cannot be error-free. We can only expect that the code is more robust and not perfect. What we can do more is how to recover from errors or find alternative solutions. CLR provides an exception handling mechanism, which not only allows people to handle exceptions more elegantly when code errors occur, but also throws exceptions when necessary. So how can we more standardize the definition and use of exception messages? Will throw exceptions affect performance?

Section 1 CLR exceptions

In early Win32 API design, true/false is returned to indicate whether a process (method or function) is successfully executed. In COM, hresult is used to indicate whether a process is correctly executed, however, this exception handling method makes it difficult for developers to find clear answers to errors, errors, and errors, the caller can easily ignore the execution results of a process. If the caller discards the execution results, the code will "run normally as expected", which is very dangerous. Later, in. NET Framework, this simple processing method that uses status codes to indicate execution results is no longer used. Instead, an exception is thrown to notify the Caller: brother, an error occurred! If you don't fix it quickly, the system will make you unable to enter the finals!

CLR exceptions are constructed based on the seh structured exception handling mechanism. In the basic seh mechanism, a callback function is registered with the system for errors. When errors occur in the monitoring area, the system will obtain control of the current thread. After processing, the system releases control to the current thread and the current thread continues to execute. If abnormal code segments are not processed, the process will be aborted. For more information about Seh, see the msdn documentation.

Based on seh encapsulation, CLR provides developers with a better programming experience in a more elegant way. It divides Exception Handling into three try, catch, and finally.

The try block is a monitoring area where some codes that normally implement programming functions, code for resource clearing, and code for status maintenance (state change and State recovery) are placed.

In the Catch Block capture area, if the try block encounters an exception and the exception type is the same as the expected type in the area, the code in the area can be executed to restore the status, you can also throw an exception again. A try block can contain catch blocks or catch blocks.

Finally blocks are used for final cleanup. In a try/catch structure, no matter whether the try throws an exception or whether the catch breaks an exception, if a Finally block exists, it will be executed at the end, the resource cleanup code is usually placed here. A try structure can have finally blocks or none.

The following is an example of using try/catch/finally blocks:

FileStream fs = null;            try            {                fs = new FileStream("c:\\file.txt", FileMode.Open);                fs.ReadByte();            }            catch (IOException)            {            }            catch            { }            finally            {                if (fs != null)                {                    fs.Close();                    fs = null;                }            }

It should be noted that a try block must have a catch block or a Finally block corresponding to it. The following methods can be used: Try... Catch, try... Finally, try... Catch. Finally.

 

Section 2 CLR Exception Handling

As mentioned above, a try block can have 0 or more catch blocks. If no exception is thrown in the try block, the CLR will not execute any catch blocks. The expressions in parentheses after the catch keyword are called the capture type. Each catch block can only specify one capture type. C # requires that the capture type only be system. ex ception class or its derived class. When an exception occurs in the try block, the CLR looks up the Catch Block that matches the exception type in the catch encoding order, therefore, the "narrow" exception type should be placed in the catch block at the beginning, and the "wide" exception type should be placed in the catch block at the end. Assume that the pseudo code of the following inheritance relationship exists:

Class class A: Class B: Class C: system. Exception

I usually put the catch filter type as follows:

try{    //}catch(A){}catch(B){}catch(C){}finally{}

If no matching type is found after the Catch Block is searched, the CLR will find the matched exception type for the call stack at the higher level. If the exception type is not found at the top of the stack, CLR throws an "unprocessed exception ". In the process of searching on the stack, if a matched Catch Block is found, execute all finally blocks in the range from the try block that throws an exception to the Catch Block that matches the exception (if any ). Note: At this time, the finally associated with the matched catch has not been executed. The Finally block is executed only after the code in the matched Catch Block is executed.

Whatever the thrown exception, the CLR throws the packaged. Net exception. That is to say, the CLR has already handled these exceptions internally, but only throws them in a more elegant and forced situation. Assume that the following call process exists:

Call method Method1 in method method0 and method method2 in method Method1. If an exception is thrown in the method method2 and no Catch Block matches the exception type, CLR will trace back the call stack to method2, Method1, and method0 to find the matched exception type, if yes, execute the relevant finally and catch blocks. If no catch block is found, an unhandled exception is thrown, as shown in the following code:

Public void method0 () {try {Method1 ();} catch {debug. writeline ("method0 catch");} finally {debug. writeline ("method0 finally") ;}} public void Method1 () {try {method2 () ;}catch (nullreferenceexception) {debug. writeline ("Method1 catch nullreferenceexception");} catch (filenotfoundexception filenot) {debug. writeline ("Method1 catch filenotfoundexception"); throw filenot;} finally {debug. Writeline ("Method1 finally") ;}} public void method2 () {filestream FS = NULL; try {// If C :\\ file.txt does not exist, the file cannot be found. FS = new filestream ("C: \ file.txt", filemode. open); FS. readbyte ();} catch (argumentexception) {debug. writeline ("method2 argumentexception");} finally {debug. writeline ("method2 finally"); If (FS! = NULL) fs. Close (); FS = NULL ;}}

In the method method2, we only want to capture argumentexception type exceptions. Obviously, nothing can be caught. In method Method1, we first expect to capture nullreferenceexception type exceptions. If not, we expect to catch a filenotfoundexception type exception. Then we will throw the exception again, in the above-level call, the method0 method uses the exception base class to capture a super wide range of exceptions! Call the method0 method in the app to view the execution process by printing the records:

        public void DoWork()        {            Method0();        }

Print:

Method2 finallyMethod1 catch FileNotFoundExceptionMethod1 finallyMethod0 catchMethod0 finally

The result verifies the CLR backtracking process for exception handling. To reduce the "length" of backtracking, we recommend that you capture possible exception types in the method method2 to reduce the CLR path.

 

Definition error in Section 3

As we have mentioned above, CLR reports program problems by throwing exceptions. Microsoft defined an exception base class: system. Exception and two Derived classes: system. systemexception and system. applicationexception. They want all system exceptions (thrown by CLR) to be derived from system. systemexception class. All exceptions thrown by applications must be derived from system. applicationexception class, but later the local staff did not listen to the management of the central staff, the results from top to bottom are not very good to follow this principle, so that when we define their own exception type, directly from the system. exception class. The general trend has become a final rule. As for which class do you like to derive from, let's look at your hobbies. In fact, we have suggested that we should derive our custom exception type from the system. exception class in the msdn document.

CLR requires that the custom exception type must be inherited from system. Exception.

FCL has defined many exception types that may be used in various scenarios, such as common:

An exception occurred when the system. argumentexception parameter is invalid. system. filenotfoundexception is used to access files that do not exist on the disk. An exception occurs when system. indexoutofrangeexception attempts to access array elements whose indexes exceed the array limit.

Although FCL still has many exception types, these are not necessarily suitable for our development needs, such as facilitating logging, facilitating the investigation of project levels, and exception messages in WCF, these special requirements may require us to define our own exception types.

Information about the exception system. exception class itself (such as message, targetsite, and innerexception) is not described here. You can query the msdn document to obtain more information. In addition to the custom exception class that must inherit from the system. exception class, we also provide some suggestions for customizing the exception type:

(1) All custom exception types should be suffixed with exception;

(2) the type and its member data should support serialization (in fact, the system. Exception type supports serialization );

(3) provide the following three constructors:

    public MyException()    {    }    public MyException(string message)    {    }    public MyException(string message, Exception inner)    {}

(4) we recommend that you override tostring () to obtain the formatting information of the exception.

(5) In a development environment that spans application boundaries, such as a service-oriented development environment, exception compatibility should be considered.

 

Section 4 throws an exception reasonably

The purpose of defining an exception is to throw an exception at the right time to tell the client that an exception has occurred. Generally, an exception is thrown in a method. When a method cannot complete a scheduled task, an exception should be thrown. When an exception is thrown, a clear exception type should be thrown instead of the basic type system. exception, system. systemexception and system. applicationexception. In section 2, we have already described that CLR is top-down looking for catch blocks, so when we throw an exception, it should also throw a clear "narrow" and "Shallow" exception type, which may be found by CLR as soon as possible. In addition, when throwing an exception type, we should describe in detail the cause, status, and possible repair measures of the exception, which is helpful for the caller to locate the problem as soon as possible, of course, in service-oriented development, you may not want to describe it in detail for security reasons. In this case, you can throw an exception code in the agreed encoding format, in this case, you may need to provide the client program with a list of descriptions corresponding to the Exception Code. Try not to use the Return Error code instead of exception. As mentioned above, the client program may ignore your returned results. If the program encounters a fatal error, Use System boldly. environment. failfast () method to terminate the program without mercy. Otherwise, running the program in a wrong state may lead to disasters. For example, your self-driving plane may go to Mars to find curiosity to fall in love.

We recommend that you avoid throwing stackoverflowexception, outofmemoryexception, comexception, sehexception, and executionengineexception.

 

Section 5 handle exceptions reasonably

Catch blocks are designed to handle exceptions. CLR gives them powerful but not supreme power. Therefore, we should use catch blocks to properly capture exceptions that we can handle, here are some suggestions for better code recovery from exceptions:

(1) If you are developing a base-class library, when an exception occurs, even if the data provided by the client program cannot allow you to complete the functional process, you must throw an exception in an arrogant manner, do not swallow it;

(2) do not write code that may cause exceptions in the Catch Block. unless an exception is thrown, do not write code that may cause a new exception in the Finally block;

(3) do not capture exceptions that you are not capable of handling. Close your door and let the CLR move up and trace back as soon as possible to find the warrior who is waiting for a fight like a cage race, he may be able to save the world;

(4) Try not to use catch (exception) to scatter the Skynet, And it will die badly;

(5) After an exception is caught, you should restore the code data from the exception as soon as possible. If you cannot reply, you should try to roll back the status. Otherwise, either you continue to throw an exception, or you can take out the powerful sword system. environment. failfast ();

(6) If you want to throw an exception for some purpose after capturing the exception, keep the stack information so that you can troubleshoot the exception at the upper layer;

 

Section 6 Obfuscation

(1) Catch Block and catch (exception) block

CLS requires that all CLR-oriented programming languages throw exception types inherited from system. Exception. In versions earlier than CLR 2.0, the catch block can only catch exceptions compatible with Cls, it cannot catch any exceptions incompatible with Cls (including exceptions thrown by other CLR-oriented programming languages ). In clr2.0, Microsoft has a new type of system. runtime. compilerservices. runtimewrappedexception: When a CLS incompatible type is thrown, CLR will instantiate a runtimewrappedexception type object, put a non-CLS compatible exception in its private field wrappedexception, and then throw runtimewrappedexception.

Catch (exception e) {} blocks. All CLS compatible and incompatible exceptions can be caught before clr2.0, but clr2.0 and later versions can only catch CLS compatible exceptions.

Catch {} blocks can catch all Cls compatibility and incompatibility exceptions in all versions.

(2) Throw and throw ex

As we mentioned earlier, CLR may use the rollback stack to find catch blocks consistent with the exception type, system. the exception class has a stacktrace attribute that records the stack trace information of an exception. It describes the method called before the exception occurs. When an exception is thrown, the CLR records the location of the throw. After the CLR traces back and finds the Catch Block, the CLR records the position of the catch, then, stacktrace is used internally to record the call (method) process between the two starting and ending positions. We modified the method Method1 in section 2nd. After capturing an exception of the filenotfoundexception type, we threw the exception again:

            catch (FileNotFoundException fileNot)            {                Debug.WriteLine("Method1 catch FileNotFoundException");                throw fileNot;                //throw;            }

First use throw filenot; check the exception stack information captured in the method0 method:

Let's take a look at the stack information that throws an exception:

We can see that the stack information after throw filenot; is the starting point from which the method is the exception stack information, and the size information after throw is from system. io. _ error. the winioerror method is the starting point. The two methods are nothing more than the starting position of the CLR to determine the exception.

The last thing to be clear is that no matter what exceptions are thrown in any scenario, Windows will reset the starting point of the stack. The stack information we get is the latest call record of the start and end methods.

 

Knot

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.