This article mainly introduces a summary of thoughts on .NET exception handling, which has certain reference value. Interested friends can refer to it.
The new year is approaching. For most programmers, it will be time to take some time off. However, in this free time, the only way to kill time is to argue about which language is better. It is estimated that this will be the case recently. There are many blog posts about java and .net. I said that as a melon-eater, I would quietly watch the big guys express their feelings.
The above nonsense is enough, so I won’t stop talking nonsense here, let’s get to the point.
In project development, there are corresponding requirements for the stability and fault tolerance of the system and code. The difference between the code in actual development projects and the sample code is more about the stability, fault tolerance, and scalability of the code's operation. Because for implementing a function, the core code to implement the function is the same, and it may just be optimized in terms of writing, but in terms of the classes used to implement a certain operation, this is the same most of the time. From this point of view, in the actual development process, we need to consider many issues, which are not limited to the implementation of a specific function, but more about the stability and scalability of the code.
The above are the problems that need to be faced in actual development. In the recent blog post, the author is also considering how to write this exception and how to understand the exception. I hope it will be helpful to everyone. , you are also welcome to put forward your own ideas and opinions, and share your knowledge and insights.
1. Overview of DotNET exceptions:
When it comes to exceptions, we need to know what exceptions are, and everything if we want to learn , we should know what we want to learn, so that we can have a general understanding in our hearts. An exception occurs when a member fails to perform the action that its name states it can perform. In .NET, there is no way to return error codes from constructors, getting and setting properties, adding and deleting events, calling operator overloads, calling conversion operators, etc. However, if errors need to be reported in these constructs, exceptions must be provided. processing mechanism.
In exception handling, the three blocks we often use are: try block; catch block; finally block. These three blocks can be used together or without a catch block. Exception handling blocks can be used nested. The specific method will be introduced below.
In the exception handling mechanism, there are generally three options: rethrow the same exception and notify the code higher in the call stack of the occurrence of the exception; throw a different exception and notify the code higher in the call stack One layer of code provides richer exception information; lets the thread exit from the bottom of the catch block.
There are some guiding suggestions on how to handle exceptions.
1. Use the finally block appropriately:
The finally block can ensure that no matter what type of exception the thread throws, it can be executed. The final block is generally used for cleanup. Those operations that have been successfully initiated will then return to the caller or the code after the finally block.
2. Exception catching needs to be appropriate:
Why should we catch exceptions appropriately? The following code, because we cannot catch all exceptions, after catching exceptions, we need to handle these exceptions. If we catch all exceptions, but do not foresee the exceptions that will occur, we will have no way to handle these exceptions. .
If the application code throws an exception, the other end of the application may expect to catch the exception, so it cannot be written as a "size-fits-all" exception block and the exception should be allowed to move up the call stack. Move and let the application code specifically handle this exception.
In the catch block, you can use System.Exception to catch exceptions, but it is best to rethrow the exception at the end of the catch block. The reason will be explained later.
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("创建注册表错误" + ex); throw new Exception(ex.Message,ex); }
3. Recovery from exceptions:
After catching the exception, we can write some targeted exception recovery methods code that allows the program to continue running. When catching exceptions, you need to catch specific exceptions, fully understand under what circumstances an exception will be thrown, and know which types are derived from the caught exception type. Do not handle or catch System.Exception exceptions unless rethrown at the end of the catch block.
4. Maintain state:
Generally, when we complete an operation or a method, we need to call several method combinations to complete it. During the execution process, It appears that the first few methods are completed, but an exception occurs in the following methods. When an unrecoverable exception occurs, the partially completed operation is rolled back, because we need to restore the information, so when we catch the exception, we need to capture all the exception information.
5. Hide implementation details to maintain the contract:
Sometimes you may need to catch an exception and rethrow a different exception, so that the contract of the method can be maintained. The type of cardiac abnormality should be a specific abnormality. Look at the following code:
FileStream fs = null; try { fs = FileStream(); } catch (FileNotFoundException e) { //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常 throw new NameNotFoundException(); } catch (IOException e) { //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常 throw new NameNotFoundException(); } finally { if (fs != null) { fs.close(); } }
以上的代码只是在说明一种处理方式。应该让抛出的所有异常都沿着方法的调用栈向上传递,而不是把他们”吞噬“了之后抛出一个新的异常。如果一个类型构造器抛出一个异常,而且该异常未在类型构造器方法中捕获,CLR就会在内部捕获该异常,并改为抛出一个新的TypeInitialztionException。
二.DotNET异常的常用处理机制:
在代码发生异常后,我们需要去处理这个异常,如果一个异常没有得到及时的处理,CLR会终止进程。在异常的处理中,我们可以在一个线程捕获异常,在另一个线程中重新抛出异常。异常抛出时,CLR会在调用栈中向上查找与抛出的异常类型匹配的catch块。如果没有任何catch块匹配抛出的异常类型,就发生一个未处理异常。CLR检测到进程中的任何线程有一个位处理异常,都会终止进程。
1.异常处理块:
(1).try块:包含代码通常需要执行一些通用的资源清理操作,或者需要从异常中恢复,或者两者都需要。try块还可以包含也许会抛出异常的代码。一个try块至少有一个关联的catch块或finall块。
(2).catch块:包含的是响应一个异常需要执行的代码。catch关键字后的圆括号中的表达式是捕获类型。捕获类型从System.Exception或者其派生类指定。CLR自上而下搜素一个匹配的catch块,所以应该教具体的异常放在顶部。一旦CLR找到一个具有匹配捕获类型的catch块,就会执行内层所有finally块中的代码,”内层finally“是指抛出异常的tey块开始,到匹配异常的catch块之间的所有finally块。
使用System.Exception捕捉异常后,可以采用在catch块的末尾重新抛出异常,因为如果我们在捕获Exception异常后,没有及时的处理或者终止程序,这一异常可能对程序造成很大的安全隐患,Exception类是所有异常的基类,可以捕获程序中所有的异常,如果出现较大的异常,我们没有及时的处理,造成的问题是巨大的。
(3).finally块:包含的代码是保证会执行的代码。finally块的所有代码执行完毕后,线程退出finally块,执行紧跟在finally块之后的语句。如果不存在finally块,线程将从最后一个catch块之后的语句开始执行。
备注:异常块可以组合和嵌套,对于三个异常块的样例,在这里就不做介绍,异常的嵌套可以防止在处理异常的时候再次出现未处理的异常,以上这些就不再赘述。
2.异常处理实例:
(1).异常处理扩展方法:
/// <summary> /// 格式化异常消息 /// </summary> /// <param name="e">异常对象</param> /// <param name="isHideStackTrace">是否隐藏异常规模信息</param> /// <returns>格式化后的异常信息字符串</returns> public static string FormatMessage(this Exception e, bool isHideStackTrace = false) { var sb = new StringBuilder(); var count = 0; var appString = string.Empty; while (e != null) { if (count > 0) { appString += " "; } sb.AppendLine(string.Format("{0}异常消息:{1}", appString, e.Message)); sb.AppendLine(string.Format("{0}异常类型:{1}", appString, e.GetType().FullName)); sb.AppendLine(string.Format("{0}异常方法:{1}", appString, (e.TargetSite == null ? null : e.TargetSite.Name))); sb.AppendLine(string.Format("{0}异常源:{1}", appString, e.Source)); if (!isHideStackTrace && e.StackTrace != null) { sb.AppendLine(string.Format("{0}异常堆栈:{1}", appString, e.StackTrace)); } if (e.InnerException != null) { sb.AppendLine(string.Format("{0}内部异常:", appString)); count++; } e = e.InnerException; } return sb.ToString(); }
(2).验证异常:
/// <summary> /// 检查字符串是空的或空的,并抛出一个异常 /// </summary> /// <param name="val">值测试</param> /// <param name="paramName">参数检查名称</param> public static void CheckNullOrEmpty(string val, string paramName) { if (string.IsNullOrEmpty(val)) throw new ArgumentNullException(paramName, "Value can't be null or empty"); } /// <summary> /// 请检查参数不是空的或空的,并抛出异常 /// </summary> /// <param name="param">检查值</param> /// <param name="paramName">参数名称</param> public static void CheckNullParam(string param, string paramName) { if (string.IsNullOrEmpty(param)) throw new ArgumentNullException(paramName, paramName + " can't be neither null nor empty"); } /// <summary> /// 检查参数不是无效,并抛出一个异常 /// </summary> /// <param name="param">检查值</param> /// <param name="paramName">参数名称</param> public static void CheckNullParam(object param, string paramName) { if (param == null) throw new ArgumentNullException(paramName, paramName + " can't be null"); } /// <summary> /// 请检查参数1不同于参数2 /// </summary> /// <param name="param1">值1测试</param> /// <param name="param1Name">name of value 1</param> /// <param name="param2">value 2 to test</param> /// <param name="param2Name">name of vlaue 2</param> public static void CheckDifferentsParams(object param1, string param1Name, object param2, string param2Name) { if (param1 == param2) { throw new ArgumentException(param1Name + " can't be the same as " + param2Name, param1Name + " and " + param2Name); } } /// <summary> /// 检查一个整数值是正的(0或更大) /// </summary> /// <param name="val">整数测试</param> public static void PositiveValue(int val) { if (val < 0) throw new ArgumentException("The value must be greater than or equal to 0."); }
(3).Try-Catch扩展操作:
/// <summary> /// 对某对象执行指定功能与后续功能,并处理异常情况 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="source">值</param> /// <param name="action">要对值执行的主功能代码</param> /// <param name="failureAction">catch中的功能代码</param> /// <param name="successAction">主功能代码成功后执行的功能代码</param> /// <returns>主功能代码是否顺利执行</returns> public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction, Action<T> successAction) where T : class { bool result; try { action(source); successAction(source); result = true; } catch (Exception obj) { failureAction(obj); result = false; } return result; } /// <summary> /// 对某对象执行指定功能,并处理异常情况 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="source">值</param> /// <param name="action">要对值执行的主功能代码</param> /// <param name="failureAction">catch中的功能代码</param> /// <returns>主功能代码是否顺利执行</returns> public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction) where T : class { return source.TryCatch(action, failureAction, obj => { }); } /// <summary> /// 对某对象执行指定功能,并处理异常情况与返回值 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <typeparam name="TResult">返回值类型</typeparam> /// <param name="source">值</param> /// <param name="func">要对值执行的主功能代码</param> /// <param name="failureAction">catch中的功能代码</param> /// <param name="successAction">主功能代码成功后执行的功能代码</param> /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns> public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction, Action<T> successAction) where T : class { TResult result; try { var u = func(source); successAction(source); result = u; } catch (Exception obj) { failureAction(obj); result = default(TResult); } return result; } /// <summary> /// 对某对象执行指定功能,并处理异常情况与返回值 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <typeparam name="TResult">返回值类型</typeparam> /// <param name="source">值</param> /// <param name="func">要对值执行的主功能代码</param> /// <param name="failureAction">catch中的功能代码</param> /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns> public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction) where T : class { return source.TryCatch(func, failureAction, obj => { }); }
本文没有具体介绍try,catch,finally的使用,而是给出一些比较通用的方法,主要是一般的开发者对于三个块的使用都有一个认识,就不再做重复的介绍。
三.DotNET的Exception类分析:
CLR允许异常抛出任何类型的实例,这里我们介绍一个System.Exception类:
1.Message属性:指出抛出异常的原因。
[__DynamicallyInvokable] public virtual string Message { [__DynamicallyInvokable] get { if (this._message != null) { return this._message; } if (this._className == null) { this._className = this.GetClassName(); } return Environment.GetRuntimeResourceString("Exception_WasThrown", new object[] { this._className }); } }
由以上的代码可以看出,Message只具有get属性,所以message是只读属性。GetClassName()获取异常的类。GetRuntimeResourceString()获取运行时资源字符串。
2.StackTrace属性:包含抛出异常之前调用过的所有方法的名称和签名。
public static string StackTrace { [SecuritySafeCritical] get { new EnvironmentPermission(PermissionState.Unrestricted).Demand(); return GetStackTrace(null, true); } }
EnvironmentPermission()用于环境限制,PermissionState.Unrestricted设置权限状态,GetStackTrace()获取堆栈跟踪,具体看一下GetStackTrace()的代码。
internal static string GetStackTrace(Exception e, bool needFileInfo) { StackTrace trace; if (e == null) { trace = new StackTrace(needFileInfo); } else { trace = new StackTrace(e, needFileInfo); } return trace.ToString(StackTrace.TraceFormat.Normal); }
public StackTrace(Exception e, bool fNeedFileInfo) { if (e == null) { throw new ArgumentNullException("e"); } this.m_iNumOfFrames = 0; this.m_iMethodsToSkip = 0; this.CaptureStackTrace(0, fNeedFileInfo, null, e); }
以上是获取堆栈跟踪方法的具体实现,此方法主要用户调试的时候。
3.GetBaseException()获取基础异常信息方法。
[__DynamicallyInvokable] public virtual Exception GetBaseException() { Exception innerException = this.InnerException; Exception exception2 = this; while (innerException != null) { exception2 = innerException; innerException = innerException.InnerException; } return exception2; }
InnerException属性是内在异常,这是一个虚方法,在这里被重写。具体看一下InnerException属性。
[__DynamicallyInvokable] public Exception InnerException { [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this._innerException; } }
4.ToString()将异常信息格式化。
private string ToString(bool needFileLineInfo, bool needMessage) { string className; string str = needMessage ? this.Message : null; if ((str == null) || (str.Length <= 0)) { className = this.GetClassName(); } else { className = this.GetClassName() + ": " + str; } if (this._innerException != null) { className = className + " ---> " + this._innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + " " + Environment.GetRuntimeResourceString("Exception_EndOfInnerExceptionStack"); } string stackTrace = this.GetStackTrace(needFileLineInfo); if (stackTrace != null) { className = className + Environment.NewLine + stackTrace; } return className; }
在此方法中,将获取的异常信息进行格式化为字符串,this.GetClassName() 获取异常类的相关信息。
以上我们注意到[__DynamicallyInvokable]定制属性,我们看一下具体的实现代码:
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public __DynamicallyInvokableAttribute() { }
以上我们主要注释部分,”图像边界“这个属性的相关信息,请参见《Via CLR c#》,这里就不做具体的介绍。
四.总结:
以上在对异常的介绍中,主要介绍了CLR的异常处理机制,一些较为通用的异常代码,以及对Exception类的介绍。在实际的项目中,我们一般不要将异常直接抛出给客户,我们在编写程序时,已经考虑程序的容错性,在程序捕获到异常后,尽量去恢复程序,或者将异常信息写入日志,让程序进入错误页。如果出现比较严重的异常,最后将异常抛出,终止程序。
The above is the detailed content of Analyze .NET exception handling. For more information, please follow other related articles on the PHP Chinese website!

PDF文件作为一种通用的文件格式,被广泛应用于各种应用场景,如电子书、报表、合同等等。在开发过程中,我们常常需要对PDF文件进行生成、编辑、读取等操作。而PHP作为一种脚本语言,也能够轻松地完成这些任务。本文将介绍使用PHP处理PDF文件的方法。一、生成PDF文件生成PDF文件有许多方法,其中最常见的是使用PDF库。PDF库是一种生成PDF文档的工具,它为

CakePHP是一个开源的Web应用程序框架,它基于PHP语言构建,可以简化Web应用程序的开发过程。在CakePHP中,处理文件上传是一个常见的需求,无论是上传头像、图片还是文档,都需要在程序中实现相应的功能。本文将介绍CakePHP中如何处理文件上传的方法和一些注意事项。在Controller中处理上传文件在CakePHP中,上传文件的处理通常在Cont

当今人工智能(AI)技术的发展如火如荼,它们在各个领域都展现出了巨大的潜力和影响力。今天大姚给大家分享4个.NET开源的AI模型LLM相关的项目框架,希望能为大家提供一些参考。https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一种开源的软件开发工具包(SDK),旨在将大型语言模型(LLM)如OpenAI、Azure

CakePHP是一个流行的PHP开发框架,它可以帮助开发者快速构建高质量的Web应用程序。随着全球化的发展,越来越多的应用需要支持多语言,CakePHP也提供了相应的支持。本文将介绍CakePHP如何处理多语言。一、多语言支持多语言支持是CakePHP的一项重要功能。从版本2.0开始,CakePHP支持gettext文件格式,该

随着现代Web应用不断发展,PHP作为其中最流行的编程语言之一,被广泛地应用于网站开发中。但在开发过程中,经常会遇到空值错误,而这些错误会导致应用程序抛出异常,进而影响用户的使用体验。因此,在PHP开发过程中,如何检测和处理空值错误,是程序员们需要掌握的重要技能。一、什么是空值错误在PHP开发过程中,空值错误通常指的是两种情况:变量未初始化和变

在进行JavaFX应用程序开发的过程中,我们常常会遇到JavaFX线程卡顿错误。这种错误的严重程度不同,可能会对程序的稳定性和性能产生不利的影响。为了保证程序的正常运行,我们需要了解JavaFX线程卡顿错误的原因和解决方法,以及如何预防这种错误的发生。一、JavaFX线程卡顿错误的原因JavaFX是一个多线程的UI应用程序框架,它允许程序在后台线程中执行长时

在企业级应用程序中,分布式系统已经成为一个常见的架构模型。分布式系统由多个处理单元(节点)组成,这些节点协同工作以完成复杂的任务。在分布式系统中,事务处理是一个必不可少的组件,因为它能够确保所有节点协同工作的结果一致性。本文将介绍如何构建基于SpringBoot的分布式事务处理。一、什么是分布式事务处理?在单节点系统中,事务处理通常是一个简单的过程。当应用


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

SublimeText3 Chinese version
Chinese version, very easy to use

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Dreamweaver Mac version
Visual web development tools