C#中throw的用法_异常路径

在C#的异常处理中,有一个关键字是throw,大家一定在catch块中或多或少的使用过,那么是否注意过不同的throw语句抛出的异常有何区别,请看下面的例子。

 

例1

class Program
    {
       static void Main(string[] args)
       {
           LoggerFileFactory.ConfigurationFilePath =Path.Combine(AppDomain.CurrentDomain.BaseDirectory,@"Config\log4net.config");
           try
           {
                Class2.Test();
            }
           catch (Exception ex)
           {
               AppLogger.ApplicationLogger.Error("err", ex);
           }
       }
    }
 
   class Class1
    {
       public static void Test()
       {
           throw new Exception("class1");
       }
    }
 
   class Class2
    {
       public static void Test()
       {
           try
           {
                Class1.Test();
           }
           catch (Exception ex)
           {
                //do something
                throw ex;
           }
       }
    }


使用log4net输出的日志如下:

 

例2

下一步,我们将Class2稍作修改

class Class2
    {
       public static void Test()
       {
           try
           {
                Class1.Test();
           }
           catch (Exception ex)
           {
                //do something
                throw;
           }
       }
    }

输出日志如下:

 

例3

我们再来修改下class2,这一次的改动稍微增大

class Class2
    {
       public static void Test()
       {
           try
           {
                Class1.Test();
           }
           catch (Exception ex)
           {
                //do something
                throw newException("class2", ex);
           }
       }
    }



       仔细观察三次的异常日志一定会有所发现,。在例1中,虽然异常的描述信息是class1,但是log4net记录的异常堆栈信息缺没有class1的踪影,只记录下了class2.Test()。而例2中的日志不只记录下了异常的描述信息,而且完整的记录下了引发异常方法的调用信息。

        不同点在哪里,请注意例1中在throw的时候使用了参数ex,而例2没有参数,这个无参的throw可以看做为rethrow(即继续抛出),他会抛出之前捕获到的所有异常。而2中带参数的则不同,他虽然会抛出同样的异常,但是异常的堆栈信息缺在throw的时候被改变了,我们在接下来的try块中无法获取异常的原始信息。例3则完全是一个新的异常,class1中抛出的异常被当做内部异常,存放在innerexception中。

 

         C#为我们提供了相当完备的异常路径,我们可以通过不同的throw方式使异常的路径可选。在实际的使用中需要根据不同的使用场景,选择不同的throw方式。比如需要查看完整的异常路径时,我们应该使用2中的方式,即不带参数的throw。
<think>在C#中,有许多内置的异常类型,它们都继承自System.Exception。以下是一些常用的异常类型及其使用场景: 1. System.Exception:所有异常的基类。 2. System.SystemException:系统运行时产生的异常基类。 3. ApplicationException:应用程序抛出的异常基类(不常用,微软建议从Exception派生自定义异常)。 4. 常见的具体异常: - ArgumentException:当方法参数无效时抛出。 - ArgumentNullException:当参数为null时抛出。 - ArgumentOutOfRangeException:当参数值超出可接受范围时抛出。 - InvalidOperationException:当对象当前状态不允许方法调用时抛出(如对已关闭的文件进行操作)。 - NotSupportedException:当调用的方法不被支持时抛出。 - NotImplementedException:当方法或操作未实现时抛出。 - NullReferenceException:当尝试访问空引用对象的成员时抛出。 - IndexOutOfRangeException:当数组索引超出范围时抛出。 - FormatException:当参数格式不符合方法要求时抛出(如字符串转换为数字时格式错误)。 - DivideByZeroException:当整数或十进制数除以零时抛出。 - FileNotFoundException:当尝试访问磁盘上不存在的文件失败时抛出。 - DirectoryNotFoundException:当尝试访问不存在的目录失败时抛出。 - IOException:输入输出操作失败时抛出的基类。 - TimeoutException:操作超时。 - SerializationException:序列化或反序列化失败时抛出。 下面我们通过代码示例来展示一些常用异常的抛出场景:</think>### C# 常用内置异常详解 在 C# 中,系统提供了丰富的内置异常类型来处理各种常见错误场景。以下是完整的分类和代码示例: ```csharp using System; using System.IO; class Program { static void Main() { // 1. 空引用异常 Console.WriteLine("=== NullReferenceException ==="); try { string text = null; Console.WriteLine(text.Length); // 访问空对象的成员 } catch (NullReferenceException ex) { Console.WriteLine($"错误: {ex.Message}\n"); } // 2. 参数异常 Console.WriteLine("=== ArgumentException ==="); try { ValidateAge(-5); // 无效参数 } catch (ArgumentOutOfRangeException ex) { Console.WriteLine($"参数错误: {ex.ParamName} - {ex.Message}\n"); } // 3. 集合操作异常 Console.WriteLine("=== Collection Exceptions ==="); try { int[] numbers = { 1, 2, 3 }; Console.WriteLine(numbers[5]); // 越界访问 } catch (IndexOutOfRangeException ex) { Console.WriteLine($"索引越界: {ex.Message}"); } try { var list = new System.Collections.Generic.List<int>(); Console.WriteLine(list[0]); // 空集合访问 } catch (ArgumentOutOfRangeException ex) { Console.WriteLine($"集合访问错误: {ex.Message}\n"); } // 4. 文件操作异常 Console.WriteLine("=== File Exceptions ==="); try { File.ReadAllText("nonexistent.txt"); // 文件不存在 } catch (FileNotFoundException ex) { Console.WriteLine($"文件未找到: {ex.FileName}"); Console.WriteLine($"错误详情: {ex.Message}\n"); } // 5. 类型转换异常 Console.WriteLine("=== Type Conversion Exceptions ==="); try { object obj = "hello"; int num = (int)obj; // 无效类型转换 } catch (InvalidCastException ex) { Console.WriteLine($"类型转换失败: {ex.Message}\n"); } // 6. 数学运算异常 Console.WriteLine("=== Arithmetic Exceptions ==="); try { int result = Divide(10, 0); // 除以零 } catch (DivideByZeroException ex) { Console.WriteLine($"数学错误: {ex.Message}\n"); } // 7. 无效操作异常 Console.WriteLine("=== InvalidOperationException ==="); try { using var reader = new StringReader("test"); reader.Close(); reader.Read(); // 尝试使用已关闭的reader } catch (InvalidOperationException ex) { Console.WriteLine($"无效操作: {ex.Message}\n"); } // 8. 格式异常 Console.WriteLine("=== FormatException ==="); try { int.Parse("abc123"); // 无效数字格式 } catch (FormatException ex) { Console.WriteLine($"格式错误: {ex.Message}\n"); } // 9. 超时异常 Console.WriteLine("=== TimeoutException ==="); try { SimulateNetworkOperation(); } catch (TimeoutException ex) { Console.WriteLine($"操作超时: {ex.Message}\n"); } // 10. 内存不足异常 Console.WriteLine("=== OutOfMemoryException ==="); try { AllocateHugeMemory(); } catch (OutOfMemoryException ex) { Console.WriteLine($"内存不足: {ex.Message}\n"); } } static void ValidateAge(int age) { if (age < 0 || age > 120) throw new ArgumentOutOfRangeException(nameof(age), "年龄必须在0-120之间"); } static int Divide(int a, int b) => a / b; static void SimulateNetworkOperation() { // 模拟网络超时 throw new TimeoutException("连接在30秒后超时"); } static void AllocateHugeMemory() { // 尝试分配超大数组 const int maxSize = int.MaxValue; var hugeArray = new byte[maxSize]; } } ``` ### C# 常用异常分类及说明: #### 1. 系统核心异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `NullReferenceException` | 访问空引用对象的成员 | `string s = null; s.Length;` | | `InvalidOperationException` | 对象处于无效状态 | 对已关闭的流进行操作 | | `NotImplementedException` | 方法尚未实现 | 占位方法体中使用 | | `NotSupportedException` | 不支持的操作 | 只读集合调用Add方法 | #### 2. 参数相关异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `ArgumentException` | 通用参数错误 | 参数格式无效 | | `ArgumentNullException` | 空参数 | 方法要求非空参数时传入null | | `ArgumentOutOfRangeException` | 参数超出有效范围 | 索引值超出集合大小 | #### 3. 集合与数组异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `IndexOutOfRangeException` | 数组索引越界 | `arr[arr.Length]` | | `KeyNotFoundException` | 字典中找不到键 | `dict["missing_key"]` | #### 4. 文件与IO异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `FileNotFoundException` | 文件不存在 | `File.Open("missing.txt")` | | `DirectoryNotFoundException` | 目录不存在 | `Directory.GetFiles("missing_dir")` | | `IOException` | 通用IO错误 | 磁盘空间不足、文件锁定等 | | `PathTooLongException` | 路径超过系统限制 | 创建超长路径文件 | #### 5. 类型与转换异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `InvalidCastException` | 无效类型转换 | `(int)"hello"` | | `FormatException` | 格式转换错误 | `int.Parse("abc")` | #### 6. 数学运算异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `DivideByZeroException` | 整数除以零 | `10 / 0` | | `OverflowException` | 算术溢出 | `int.MaxValue + 1` | #### 7. 资源相关异常 | 异常类型 | 使用场景 | 示例 | |----------|----------|------| | `OutOfMemoryException` | 内存不足 | 分配超大数组 | | `StackOverflowException` | 栈溢出 | 无限递归调用 | | `TimeoutException` | 操作超时 | 网络请求超时 | ### 异常处理最佳实践: 1. **优先使用具体异常**:捕获最具体的异常类型 2. **避免捕获通用异常**:除非在顶层处理未知错误 3. **提供有意义的错误信息**:包含相关参数和状态 4. **使用异常过滤器**:C# 6.0+ 支持 `when` 子句 5. **避免异常滥用**:不要用异常处理正常控制流 6. **清理资源**:使用 `using` 或 `finally` 确保资源释放 ### 异常层次结构概览: ``` System.Exception ├── System.SystemException │ ├── ArgumentException │ │ ├── ArgumentNullException │ │ └── ArgumentOutOfRangeException │ ├── NullReferenceException │ ├── IndexOutOfRangeException │ ├── InvalidOperationException │ ├── FormatException │ ├── InvalidCastException │ ├── IOException │ │ ├── FileNotFoundException │ │ └── DirectoryNotFoundException │ ├── ArithmeticException │ │ ├── DivideByZeroException │ │ └── OverflowException │ └── TimeoutException └── System.ApplicationException ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值