前言
异常是在程序执行过程中发生的意外情况,例如除以零、访问 null 对象或遇到 file not found 错误。C#提供使用try、catch和finally块处理的可靠机制。异常处理有助于处理在程序运行期间发生的任何意外或异常情况,异常是使用 throw 关键字创建而成。
正确管理异常是开发健壮的应用程序的一个关键方面。管理好异常的好坏意味着平稳运行的应用程序与故障排除的噩梦之间的区别。
在C#中引发异常的三种常见方法是throw、throw ex 和 throw new Exception(ex),尽管它们看起来很相似,但它们都有不同的行为和实例。本文探讨它们的差异,并以示例介绍每种方法使用。
基础知识
1、throw 语句
throw 语句用于指示异常的发生。用于显式地引发异常或重新引发捕获的异常。使用 throw 语句重新引发异常时,它会保留原始异常的堆栈跟踪,这对于调试至关重要。
下面示例:throw 语句会重新引发捕获的异常,同时保留原始堆栈跟踪。
try{ //文件不存在 string content= File.ReadAllText(string.Format("{0}{1}log.txt",AppDomain.CurrentDomain.BaseDirectory,Path.DirectorySeparatorChar),Encoding.UTF8);}catch (Exception ex){ Console.WriteLine(ex.Message); throw;}
2、throw ex 语句
throw ex 语句是重新引发异常的另一种方法。但是,与 throw 不同的是,throw ex 会重置堆栈跟踪信息。这意味着新的堆栈跟踪从调用 throw ex 的点开始,丢失发生异常的原始上下文。
下面示例:throw ex 会重新引发捕获的异常,但堆栈跟踪将从 catch 块开始,这可能会掩盖异常的根本原因。
try
{ int firstnum = 1; int secondnum = 0; Console.WriteLine(firstnum / secondnum);}catch (Exception ex){ Console.WriteLine(ex.Message); throw ex;}
3、throw new Exception 语句
throw new Exception() 是将原始异常包装在新异常中,提供额外的上下文,同时仍包含原始异常。
下面示例:将使用自定义消息创建新异常,并将原始异常作为内部异常传递。这提供了额外的上下文,同时保留原异常的详细信息。
try{ // log.txt 文件不存在 string content= File.ReadAllText(string.Format("{0}{1}log.txt",AppDomain.CurrentDomain.BaseDirectory,Path.DirectorySeparatorChar),Encoding.UTF8);}catch (Exception ex){ Console.WriteLine(ex.Message); throw new Exception("【log.txt】文件不存", ex);}
三者区别
1、堆栈跟踪
throw:保留原始堆栈跟踪,提供有关异常来源的完整信息。
throw ex:重置堆栈跟踪,这可能会使调试异常的根本原因发生改变。
throw new Exception:为新的异常消息提供其他上下文,同时将原始异常保留为内部异常。
2、应用场景
throw:需维护原始异常上下文和堆栈跟踪时,使用该方法。
throw ex:该方法谨慎,如需使用,应在重新引发异常之前向异常添加其他信息。
throw new Exception:如果需要往异常添加更多上下文,同时保留原始异常详细信息,使用该方式。
示例
1、使用 throw
using System;using System.Collections.Generic;using System.Linq;using System.Text;
namespace Fountain.WinConsole.ExceptionDemo{ public class UserBiz { /// <summary> /// 登录 /// </summary> public void Login() { try { UserDiz userDiz = new UserDiz(); userDiz.GetUserData(); } catch (Exception ex) { throw; } } }
public class UserDiz { /// <summary> /// 获取用户数据 /// </summary> public void GetUserData() { try { throw new InvalidOperationException("用户或密码不正确!"); } catch (Exception ex) { throw; } } }}
堆栈跟踪将指向 GetUserData 中异常的原始来源,从而更容易调试。

2、使用 throw ex
using System;using System.Collections.Generic;using System.Linq;using System.Text;
namespace Fountain.WinConsole.ExceptionDemo{ public class UserBiz { /// <summary> /// 登录 /// </summary> public void Login() { try { UserDiz userDiz = new UserDiz(); userDiz.GetUserData(); } catch (Exception ex) { throw ex; } } }
public class UserDiz { /// <summary> /// 获取用户数据 /// </summary> public void GetUserData() { try { throw new InvalidOperationException("用户或密码不正确!"); } catch (Exception ex) { throw ex; } } }}
堆栈跟踪将仅显示重新抛出点(Login),而不显示异常的原始来源(GetUserData),从而更难确定错误最初发生的位置。

3、使用 throw new Exception
using System;using System.Collections.Generic;using System.Linq;using System.Text;
namespace Fountain.WinConsole.ExceptionDemo{ public class UserBiz { /// <summary> /// 登录 /// </summary> public void Login() { try { UserDiz userDiz = new UserDiz(); userDiz.GetUserData(); } catch (Exception ex) { throw new Exception("用户登录异常", ex); } } }
public class UserDiz { /// <summary> /// 获取用户数据 /// </summary> public void GetUserData() { try { throw new InvalidOperationException("用户或密码不正确!"); } catch (Exception ex) { throw new Exception("获取用户数据异常", ex); } } }}
新异常提供了额外的上下文,例如发生错误的方法名称,同时仍保留原始异常详细信息。
效果:

using System;
namespace Fountain.WinConsole.ExceptionDemo{ class Program { static void Main(string[] args) { try { UserBiz userBiz = new UserBiz(); userBiz.Login(); } catch(Exception ex) { if (ex.InnerException != null) { Console.WriteLine(string.Format("{0}{1}{2}", ex.InnerException.Message, Environment.NewLine, ex.InnerException.StackTrace)); Console.WriteLine(string.Format("{0}{1}{2}", ex.Message, Environment.NewLine, ex.StackTrace)); } else { Console.WriteLine(string.Format("{0}{1}{2}", ex.Message, Environment.NewLine, ex.StackTrace)); } } Console.ReadKey(); } }}
小结
处理异常时,在throw、throw ex和throw new Exception 三者间进行选择,对于有效处理异常和调试非常重要。从上面了解,throw 语句通常是首选,throw ex 需谨慎使用,对于throw new Exception则可用于复杂应用。
该文章在 2024/10/22 15:16:52 编辑过