The end of the year, for most programmers, will be free for a while now, however, in this free time, only the debate which language is better to kill time, it is estimated that recently there will be a lot of Java and. NET Bowen appeared, I said to as a eat melon masses, quietly watching the big guys express mood.
More than enough nonsense, here is no longer nonsense, or cut to the point of it.
In the project development, the system and code stability and fault tolerance are corresponding requirements. The difference between code and sample code in the actual development project is more a comparison of the stability, fault tolerance and extensibility of the code running. Because the core code for implementing functionality is the same for implementing a feature, it may only be optimized in writing, but this is most often the case when implementing a class that is used in an operation. So, we in the actual development process, we need to consider more problems, has not limited to a specific function to achieve, more is the stability of the code and scalability considerations.
These are the problems that need to be faced in the actual development, the author in the recent blog, also consider this anomaly in the end need how to write, as well as the abnormal need how to understand, I hope to have a help, but also welcome everyone to put forward their own ideas and opinions, share their knowledge and insights.
I. Overview of dotnet Exceptions:
When it comes to anomalies, we need to know what is called an anomaly, and all things if we want to learn, we should know what we want to learn, so that in the mind there is a general understanding. An exception is an action that a member does not complete with its name claiming to be complete. In. NET, constructors, get and set properties, add and remove events, call operator overloads, and invoke conversion operators, and so on, have no way to return error codes, but in these constructs you need to report errors, and you must provide an exception handling mechanism.
In the handling of exceptions, the three blocks that we often use are: try blocks, catch blocks, finally blocks. These three blocks can be used together or not to write catch blocks, and exception handling blocks can be nested using, as described below.
In the exception processing mechanism, there are generally three kinds of choices: re-throw the same exception, the call stack to the top layer of code to inform the occurrence of the exception, throw a different exception, want to call the stack layer of code to provide richer exception information; Let the thread exit from the bottom of the catch block.
There are some instructive suggestions about how exceptions are handled.
1. Proper use of finally blocks:
Finally blocks can guarantee that any type of exception that is not thrown by the pipeline can be executed, and the Finall block is typically used to clean up those operations that have been successfully started, and then return the code after the caller or finally block.
2. Abnormal capture should be appropriate:
Why should we catch the exception properly? The following code, because we can't catch any exceptions, we need to deal with the exceptions after we catch them, and if we catch all the exceptions, but we don't anticipate the anomalies, we can't handle them.
If the application code throws an exception, the other end of the application may be expected to catch the exception, so it cannot be written as a "size all" exception block, and should allow the exception to move up the call stack, allowing the application code to address the exception specifically.
In a catch block, you can use System.Exception to catch exceptions, but it is a good idea to throw them back at the end of a catch block. The reason will be explained later.
The code is as follows |
Copy Code |
Try
{
var hkml = Getregistrykey (ROOTKEY);
var subkey = Hkml. CreateSubKey (subkey);
If (subkey!=null&& KeyName!=string. Empty)
subkey. SetValue (KeyName, KeyValue, registryvaluekind.string);
}
catch (Exception ex)
{
Log4helper.error ("Create registry Error" + ex);
Thrownewexception (ex. MESSAGE,EX);
}
|
3. Recover from the exception:
After we catch the exception, we can write some abnormal recovery code, so that the program can continue to run. When you catch an exception, you need to catch a specific exception, fully grasp the circumstances in which the exception is thrown, and know which types derive from the captured exception type. Do not handle or catch System.Exception exceptions unless the exception is thrown again at the end of the catch block.
4. Maintenance Status:
In general, when we complete an operation or a method, we need to call several method combinations to complete, and in the process of execution, there will be several previous methods, followed by an exception to the method. Rollback partially completed operations when an unrecoverable exception occurs because we need to recover the information and all the exception information we need to catch when we catch the exception.
5. Hide the implementation details to maintain the contract:
Sometimes it may be necessary to catch an exception and throw a different exception, so that the contract of the method can be maintained, and the type of the thrown heart exception should be a specific exception. Look at the following code:
The code is as follows |
Copy Code |
catch (FileNotFoundException e)
Throws a different exception, contains the exception information, and sets the original exception to an inner exception
Thrownewnamenotfoundexception ();
Throws a different exception, contains the exception information, and sets the original exception to an inner exception
Thrownewnamenotfoundexception ();
|
The above code is just a way of describing a process. All the exceptions thrown should be passed up the call stack of the method instead of "devouring" them and throwing a new exception. If a type constructor throws an exception, and the exception is not captured in the type constructor method, the CLR catches the exception internally and throws a new typeinitialztionexception instead.
Two. Common processing mechanisms for dotnet anomalies:
After the code has an exception, we need to handle the exception, and if an exception is not processed in time, the CLR terminates the process. In handling exceptions, we can catch an exception on one thread and throw it back in another thread. When an exception is thrown, the CLR looks up a catch block that matches the thrown exception type in the call stack. If no catch block matches the thrown exception type, an unhandled exception occurs. The CLR detects that any thread in the process has a bit handle exception and terminates the process.
1. Exception Handling BLOCK:
(1). Try block: The containing code usually requires some common resource cleanup operations, or it needs to be recovered from the exception, or both. A try block can also contain code that might throw an exception. A try block has at least one associated catch block or Finall block.
(2). Catch block: Contains code that responds to an exception that needs to be executed. The expression in the parentheses after the Catch keyword is the capture type. The capture type is specified from System.Exception or its derived class. The CLR searches for a matching catch block from top to bottom, so you should teach the specific exception to be placed at the front. Once the CLR finds a catch block with a matching catch type, the code in all finally blocks in the inner layer is executed, and "inner finally" refers to all finally blocks between the Tey block that throws the exception and the catch block that matches the exception.
After you use System.Exception to catch an exception, you can throw the exception back at the end of the catch block, because if we do not process or terminate the program in a timely manner after capturing the exception exception, this exception can pose a significant security risk to the program, and the exception class is the base class for all exceptions and can be Catch all the exceptions in the program, if there is a large exception, we do not timely processing, causing the problem is enormous.
(3). Finally block: The contained code is the code that guarantees execution. After all of the code for the finally block executes, the thread exits the finally block and executes the statement immediately following the finally block. If a finally block does not exist, the thread begins execution from the statement following the last catch block.
Note: Exception blocks can be combined and nested, for example of three exception blocks, here is not to introduce, the exception of nesting can prevent the exception when handling the unhandled exception, these are no longer repeat.
2. Exception Handling Example:
(1). Exception Handling Extension methods:
The code is as follows |
Copy Code |
Formatting an exception message
<param name= "E" > Exception object </param>
<param name= "Ishidestacktrace" > whether to hide abnormal scale information </param>
<returns> formatted exception information string </returns>
Publicstaticstringformatmessage (thisexception e,boolishidestacktrace =false)
var sb =newstringbuilder ();
var appstring =string. Empty;
Sb. Appendline (String. Format ("{0} Exception message: {1}", Appstring, E.message));
Sb. Appendline (String. Format (' {0} exception type: {1} ', Appstring, E.gettype (). FullName));
Sb. Appendline (String. Format (' {0} exception method: {1} ', Appstring, (E.targetsite ==null?null:e.targetsite.name)));
Sb. Appendline (String. Format ("{0} exception Source: {1}", Appstring, E.source));
if (!ishidestacktrace && e.stacktrace!=null)
Sb. Appendline (String. Format ("{0} exception stack: {1}", Appstring, E.stacktrace));
if (e.innerexception!=null)
Sb. Appendline (String. Format ("{0} Internal exception:", appstring));
|
The code is as follows |
Copy Code |
(2). Validation exception:
Checks that the string is empty or empty and throws an exception
<param name= "val" > Value Test </param>
<param name= "paramname" > Parameter check name </param>
Publicstaticvoidchecknullorempty (Stringval,stringparamname)
if (string. IsNullOrEmpty (Val))
Thrownewargumentnullexception (paramname, "Value can ' t be null or empty");
Please check that the parameter is not empty or empty and throw an exception
<param name= "param" > Check value </param>
<param name= "paramname" > Parameter name </param>
Publicstaticvoidchecknullparam (Stringparam,stringparamname)
if (string. IsNullOrEmpty (param))
Thrownewargumentnullexception (paramname, paramname + "can ' t be neither null nor empty");
Check that the parameter is not invalid and throw an exception
<param name= "param" > Check value </param>
<param name= "paramname" > Parameter name </param>
Publicstaticvoidchecknullparam (Objectparam,stringparamname)
Thrownewargumentnullexception (paramname, paramname + "can ' t be null");
Please check that parameter 1 is different from parameter 2
<param name= "param1" > value 1 Test </param>
<param name= "Param1name" >name of Value 1</param>
<param name= "param2" >value 2 to Test</param>
<param name= "Param2name" >name of Vlaue
Publicstaticvoidcheckdifferentsparams (Objectparam1,stringparam1name,objectparam2,stringparam2name)
Thrownewargumentexception (Param1name + "can" t be the same as "+ Param2name,
Param1name + "and" + param2name);
Check that an integer value is positive (0 or greater)
<param name= "val" > Integer test </param>
Publicstaticvoidpositivevalue (Intval)
Thrownewargumentexception ("The value must be greater than or equal to 0.");
|
(3). Try-catch extension Operations:
The code is as follows |
Copy Code |
Performs specified and subsequent functions on an object and handles exceptions
<typeparam name= "T" > Object type </typeparam>
<param name= "source" > Value </param>
<param name= "Action" > main function code to perform on value </param>
<param name= "failureaction" >catch function code </param>
<param name= "successaction" > main function code executed after the successful function code </param>
<returns> The main function code is executed smoothly </returns>
Publicstaticbooltrycatch<t> (thist source, action<t> Action, action<exception> failureAction,
Action<t> successaction) where T:class
Performs the specified function on an object and handles exception conditions
<typeparam name= "T" > Object type </typeparam>
<param name= "source" > Value </param>
<param name= "Action" > main function code to perform on value </param>
<param name= "failureaction" >catch function code </param>
<returns> The main function code is executed smoothly </returns>
Publicstaticbooltrycatch<t> (thist source, action<t> Action, action<exception> failureAction) where T:class
Returnsource. TryCatch (Action,
Performs the specified function on an object and handles exception conditions and return values
<typeparam name= "T" > Object type </typeparam>
<typeparam name= "TResult" > Return value type </typeparam>
<param name= "source" > Value </param>
<param name= "func" > main function code to perform on value </param>
<param name= "failureaction" >catch function code </param>
<param name= "successaction" > main function code executed after the successful function code </param>
<returns> return value of the function code, if an exception occurs, returns the default value of the object type </returns>
Publicstatictresult trycatch<t, tresult> (thist source, func<t, tresult> Func, action<exception> Failureaction,
Result =default (TResult);
Performs the specified function on an object and handles exception conditions and return values
<typeparam name= "T" > Object type </typeparam>
<typeparam name= "TResult" > Return value type </typeparam>
<param name= "source" > Value </param>
<param name= "func" > main function code to perform on value </param>
<param name= "failureaction" >catch function code </param>
<returns> return value of the function code, if an exception occurs, returns the default value of the object type </returns>
Publicstatictresult trycatch<t, tresult> (thist source, func<t, tresult> Func, action<exception> Failureaction)
Returnsource. TryCatch (func,
|
This article does not specifically introduce the use of try,catch,finally, but to give some more general methods, mainly the general developers for the use of three blocks have a knowledge, no longer do repeat introduction.
Three. Analysis of the exception class of dotnet:
The CLR allows exceptions to throw any type of instance, and here we introduce a System.Exception class:
1.Message Property: Indicates why the exception was thrown.
The code is as follows |
Copy Code |
[__dynamicallyinvokable]
Publicvirtualstringmessage
{
[__dynamicallyinvokable]
Get
{
if (This._message!=null)
{
Returnthis._message;
}
if (This._classname ==null)
{
This._classname =this. GetClassName ();
}
Returnenvironment.getruntimeresourcestring ("Exception_wasthrown", newobject[] {this._classname});
}
}
|
As you can see from the above code, the message has only a Get property, so the message is read-only. GetClassName () Gets the class of the exception. Getruntimeresourcestring () Gets the Run-time resource string.
2.StackTrace property: Contains the name and signature of all methods that were called before the exception was thrown.
code is as follows |
copy code |
publicstaticstring StackTrace
{
[securitysafecritical]
get
{
newenvironmentpermission (permissionstate.unrestricted). Demand ();
returngetstacktrace (null,true);
}
|
EnvironmentPermission () is used for environmental restrictions, permissionstate.unrestricted sets the permission state, Getstacktrace () Gets the stack trace, and look at the code for Getstacktrace ().
The code is as follows |
Copy Code |
internalstaticstring getstacktrace (Exception E, bool needfileinfo)
{
stacktrace trace;
if (e ==null)
{
trace =newstacktrace (Needfileinfo);
else
{
trace =newstacktrace (E, needfileinfo);
}
returntrace. ToString (StackTrace.TraceFormat.Normal);
}
Publicstacktrace (Exception E, bool fneedfileinfo)
{
if (e ==null)
{
Thrownewargumentnullexception ("E");
}
This.m_inumofframes = 0;
This.m_imethodstoskip = 0;
This. Capturestacktrace (0, Fneedfileinfo,null, e);
}
|
The above is to obtain the implementation of the stack tracking method, the main user debugging time.
3.GetBaseException () Gets the underlying exception information method.
The code is as follows |
Copy Code |
[__dynamicallyinvokable]
Publicvirtualexception GetBaseException ()
{
Exception innerexception =this. innerexception;
Exception Exception2 =this;
while (InnerException!=null)
{
Exception2 = innerexception;
innerexception = innerexception.innerexception;
}
Returnexception2;
}
|
The InnerException attribute is an intrinsic exception, which is a virtual method, which is overridden here. Take a specific look at the InnerException property.
The code is as follows |
Copy Code |
[__dynamicallyinvokable]
Publicexception innerexception
{
[__dynamicallyinvokable, Targetedpatchingoptout ("performance critical to inline this type of method across NGen image Boun Daries ")]
Get
{
Returnthis._innerexception;
}
}
|
4.ToString () format the exception information.
The code is as follows |
Copy Code |
Privatestringtostring (Boolneedfilelineinfo,boolneedmessage)
Stringstr = Needmessage? this. Message:null;
if (str ==null) | | (str. Length <= 0))
ClassName =this. GetClassName ();
ClassName =this. GetClassName () + ":" + str;
if (this._innerexception!=null)
ClassName = className + "--->" +this._innerexception.tostring (Needfilelineinfo, needmessage) + Environment.NewLine + "" + environment.getruntimeresourcestring ("Exception_endofinnerexceptionstack");
Stringstacktrace =this. Getstacktrace (Needfilelineinfo);
ClassName = className + Environment.NewLine + stacktrace;
|
In this method, the obtained exception information is formatted as a string, this. GetClassName () Gets information about the exception class.
Above we note [__dynamicallyinvokable] custom attributes, let's look at the specific implementation code:
The code is as follows |
Copy Code |
[Targetedpatchingoptout ("Performance critical to inline this type of method across NGen image boundaries")]
Public__dynamicallyinvokableattribute ()
{
}
|
Above our main annotation section, "image boundary" This attribute information, see "Via CLR C #", here is not a specific introduction.
Four. Summary:
Above in the introduction of the exception, the main introduction of the CLR exception handling mechanism, some more general exception code, as well as the introduction of the Exception class. In the actual project, we generally do not throw the exception directly to the customer, we write the program, we have considered the fault tolerance of the program, after the program caught the exception, as far as possible to restore the program, or the exception information to the log, so that the program into the error page. If a more serious exception occurs, the exception is thrown, terminating the program.