C#个人学习笔记之异常的介绍,处理和捕获--007
·
C# 异常处理详解
一、什么是异常
异常(Exception):程序运行过程中出现的非预期错误,比如除0、数组越界、空引用、文件不存在等。
C# 中所有异常都派生自 System.Exception 基类,属于运行时错误,语法错误编译阶段就会拦截。
常见系统内置异常
| 异常类 | 说明 |
|---|---|
NullReferenceException |
空引用异常(对象为null却调用成员) |
IndexOutOfRangeException |
数组/集合下标越界 |
DivideByZeroException |
整数除以0 |
FileNotFoundException |
文件未找到 |
ArgumentNullException |
方法传入null参数 |
二、C# 异常处理核心关键字
C# 使用 try、catch、finally、throw 四大关键字处理异常。
1. try-catch 基础结构
作用:监控可能出错的代码,捕获异常并处理,避免程序直接崩溃。
using System;
class Program
{
static void Main()
{
try
{
// 可能出现异常的代码
int a = 10;
int b = 0;
int res = a / b; // 触发除0异常
Console.WriteLine("执行正常");
}
catch (DivideByZeroException ex)
{
// 捕获并处理 指定类型异常
Console.WriteLine($"捕获到除0异常:{ex.Message}");
}
Console.WriteLine("程序继续运行...");
}
}
2. 多 catch 块(捕获多种异常)
多个catch从上到下匹配,先写子类异常,后写父类异常,顺序不能颠倒。
try
{
int[] arr = { 1, 2, 3 };
arr[5] = 10; // 数组越界
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"数组越界:{ex.Message}");
}
catch (NullReferenceException ex)
{
Console.WriteLine($"空引用:{ex.Message}");
}
catch (Exception ex)
{
// 万能捕获:所有异常的父类,放最后
Console.WriteLine($"未知异常:{ex.Message}");
}
3. try-catch-finally 结构
finally 特点:无论是否发生异常,代码一定会执行。
适用场景:释放资源(关闭文件、数据库连接、网络流)。
try
{
Console.WriteLine("执行业务代码");
int num = 1 / 0;
}
catch (Exception ex)
{
Console.WriteLine($"异常:{ex.Message}");
}
finally
{
// 必定执行,用于资源释放
Console.WriteLine("finally 资源释放");
}
4. try-finally(无catch)
只监控代码、释放资源,不捕获异常,异常会继续向上抛出。
try
{
// 可能出错代码
}
finally
{
// 释放资源
}
三、throw 抛出异常
1. 主动抛出系统异常
手动触发异常,用于参数校验、逻辑拦截。
static void CheckAge(int age)
{
if (age < 0)
{
// 主动抛出参数异常
throw new ArgumentOutOfRangeException(nameof(age), "年龄不能为负数");
}
Console.WriteLine($"年龄合法:{age}");
}
// 调用
try
{
CheckAge(-5);
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine(ex.Message);
}
2. 异常向上传递(throw 单独使用)
在catch中使用 throw; 可把当前异常继续向上抛出,交由上层调用者处理。
static void Test()
{
try
{
int a = 1 / 0;
}
catch (Exception ex)
{
Console.WriteLine("内层捕获,继续上抛");
throw; // 异常向上传递
}
}
static void Main()
{
try
{
Test();
}
catch (Exception ex)
{
Console.WriteLine("外层捕获:" + ex.Message);
}
}
四、Exception 常用属性
异常对象ex常用成员,用于排查错误:
try
{
int a = 1 / 0;
}
catch (Exception ex)
{
Console.WriteLine($"异常描述:{ex.Message}"); // 错误简要信息
Console.WriteLine($"异常来源:{ex.Source}"); // 出错程序集
Console.WriteLine($"调用栈:{ex.StackTrace}"); // 报错代码位置(排错核心)
Console.WriteLine($"内部异常:{ex.InnerException}"); // 嵌套异常
}
五、自定义异常(重点)
当系统内置异常无法满足业务需求时,自定义异常类,规范业务报错。
步骤
- 新建类,继承自
Exception - 实现三个构造函数(C# 规范写法)
示例:自定义业务异常
// 自定义用户操作异常
public class UserOperationException : Exception
{
// 无参构造
public UserOperationException() { }
// 带错误信息构造
public UserOperationException(string message) : base(message) { }
// 错误信息 + 内部异常(异常嵌套)
public UserOperationException(string message, Exception innerEx)
: base(message, innerEx) { }
}
// 使用自定义异常
class Program
{
static void Login(string userName)
{
if (string.IsNullOrEmpty(userName))
{
// 抛出自定义异常
throw new UserOperationException("用户名不能为空!");
}
Console.WriteLine("登录成功");
}
static void Main()
{
try
{
Login("");
}
catch (UserOperationException ex)
{
Console.WriteLine($"业务异常:{ex.Message}");
}
}
}
六、异常处理最佳实践(面试/开发常用)
- 不要滥用 try-catch
正常逻辑不要加捕获,只处理可预见的异常。 - 精准捕获异常
优先捕获具体异常,少直接用catch(Exception)一网打尽。 - 资源释放写在 finally
文件、数据库、网络连接必须在finally关闭。 - 不要空 catch
catch{}隐藏错误,难以排错,禁止使用。 - 异常分层处理
底层抛出异常,上层统一捕获、日志记录、友好提示。 - 自定义异常用于业务场景
区分系统错误和业务错误,便于维护。
七、补充:checked / unchecked 溢出检查
针对数值溢出异常:
checked:开启溢出检查,溢出直接抛OverflowExceptionunchecked:关闭溢出检查(默认)
// 开启溢出检测
checked
{
int max = int.MaxValue;
max++; // 抛出溢出异常
}
笔记总结
- 四大关键字:
try(监控)、catch(捕获)、finally(释放资源)、throw(抛异常) - 异常继承链:所有异常 →
Exception - 多
catch遵循先子类、后父类 finally必执行,专用于资源回收- 业务场景推荐自定义异常,代码更规范
- 开发原则:精准捕获、不吞异常、合理抛异常
更多推荐
所有评论(0)