异常处理概述 #

一、异常概述 #

异常是程序运行时发生的错误,C#通过异常处理机制来捕获和处理这些错误。

1.1 异常特点 #

  • 打断正常程序流程
  • 包含错误信息
  • 可以被捕获和处理
  • 沿调用栈传播

1.2 异常处理的好处 #

  • 分离正常逻辑和错误处理
  • 统一的错误处理机制
  • 丰富的错误信息
  • 强制处理错误

二、异常类层次结构 #

2.1 基本结构 #

text
System.Object
    └── System.Exception
            ├── System.SystemException
            │       ├── ArgumentException
            │       ├── ArgumentNullException
            │       ├── ArgumentOutOfRangeException
            │       ├── ArithmeticException
            │       │       ├── DivideByZeroException
            │       │       ├── OverflowException
            │       │       └── NotFiniteNumberException
            │       ├── FormatException
            │       ├── IndexOutOfRangeException
            │       ├── InvalidOperationException
            │       ├── NullReferenceException
            │       ├── OutOfMemoryException
            │       └── StackOverflowException
            ├── ApplicationException
            ├── IOException
            │       ├── FileNotFoundException
            │       ├── DirectoryNotFoundException
            │       └── EndOfStreamException
            └── UnauthorizedAccessException

2.2 Exception类属性 #

csharp
public class Exception
{
    public virtual string Message { get; }
    public virtual string StackTrace { get; }
    public Exception InnerException { get; }
    public string Source { get; set; }
    public MethodBase TargetSite { get; }
    public string HelpLink { get; set; }
    public IDictionary Data { get; }
}

2.3 获取异常信息 #

csharp
try
{
    int result = 10 / 0;
}
catch (Exception ex)
{
    Console.WriteLine($"消息:{ex.Message}");
    Console.WriteLine($"类型:{ex.GetType().Name}");
    Console.WriteLine($"堆栈:{ex.StackTrace}");
    Console.WriteLine($"来源:{ex.Source}");
}

三、异常分类 #

3.1 系统异常 #

由CLR抛出的异常:

异常 说明
NullReferenceException 空引用异常
IndexOutOfRangeException 索引越界
DivideByZeroException 除零异常
OverflowException 溢出异常
OutOfMemoryException 内存不足
StackOverflowException 栈溢出
csharp
string s = null;
Console.WriteLine(s.Length);

int[] arr = new int[5];
Console.WriteLine(arr[10]);

int x = 10, y = 0;
int result = x / y;

checked
{
    int max = int.MaxValue + 1;
}

3.2 应用程序异常 #

由应用程序抛出的异常:

异常 说明
ArgumentException 参数异常
ArgumentNullException 参数为空
ArgumentOutOfRangeException 参数超出范围
FormatException 格式错误
InvalidOperationException 无效操作
csharp
public void SetAge(int age)
{
    if (age < 0)
        throw new ArgumentOutOfRangeException(nameof(age), "年龄不能为负数");
    
    if (age > 150)
        throw new ArgumentOutOfRangeException(nameof(age), "年龄超出合理范围");
}

public void Process(string data)
{
    if (data == null)
        throw new ArgumentNullException(nameof(data));
    
    if (string.IsNullOrWhiteSpace(data))
        throw new ArgumentException("数据不能为空", nameof(data));
}

3.3 I/O异常 #

文件和输入输出相关异常:

异常 说明
IOException I/O操作异常
FileNotFoundException 文件未找到
DirectoryNotFoundException 目录未找到
PathTooLongException 路径过长
UnauthorizedAccessException 访问被拒绝
csharp
try
{
    string content = File.ReadAllText("nonexistent.txt");
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"文件未找到:{ex.FileName}");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("没有访问权限");
}
catch (IOException ex)
{
    Console.WriteLine($"I/O错误:{ex.Message}");
}

四、常见异常场景 #

4.1 空引用异常 #

csharp
string name = null;

if (name != null)
{
    Console.WriteLine(name.Length);
}

Console.WriteLine(name?.Length ?? 0);

4.2 类型转换异常 #

csharp
object obj = "Hello";

if (obj is int number)
{
    Console.WriteLine(number);
}

if (int.TryParse("123", out int result))
{
    Console.WriteLine(result);
}

4.3 集合操作异常 #

csharp
var list = new List<int>();

if (list.Count > 0)
{
    var first = list[0];
}

var firstOrDefault = list.FirstOrDefault();

var dict = new Dictionary<string, int>();
if (dict.TryGetValue("key", out int value))
{
    Console.WriteLine(value);
}

4.4 文件操作异常 #

csharp
string path = "test.txt";

if (File.Exists(path))
{
    string content = File.ReadAllText(path);
}

try
{
    using var stream = File.OpenRead(path);
}
catch (FileNotFoundException)
{
    Console.WriteLine("文件不存在");
}

五、异常传播 #

5.1 调用栈传播 #

csharp
public void MethodA()
{
    MethodB();
}

public void MethodB()
{
    MethodC();
}

public void MethodC()
{
    throw new Exception("MethodC中的异常");
}

5.2 内部异常 #

csharp
public void LoadConfig(string path)
{
    try
    {
        string content = File.ReadAllText(path);
        ParseConfig(content);
    }
    catch (Exception ex)
    {
        throw new ConfigurationException("配置加载失败", ex);
    }
}

public class ConfigurationException : Exception
{
    public ConfigurationException(string message, Exception innerException)
        : base(message, innerException)
    {
    }
}

六、异常最佳实践 #

6.1 避免使用异常控制流程 #

csharp
if (int.TryParse(input, out int number))
{
    Process(number);
}
else
{
    Console.WriteLine("输入无效");
}

try
{
    int number = int.Parse(input);
    Process(number);
}
catch (FormatException)
{
    Console.WriteLine("输入无效");
}

6.2 抛出有意义的异常 #

csharp
public void Withdraw(decimal amount)
{
    if (amount <= 0)
        throw new ArgumentException("取款金额必须大于0", nameof(amount));
    
    if (amount > _balance)
        throw new InvalidOperationException("余额不足");
    
    _balance -= amount;
}

6.3 使用特定异常类型 #

csharp
public void Process(string value)
{
    if (value == null)
        throw new ArgumentNullException(nameof(value));
    
    if (value.Length == 0)
        throw new ArgumentException("值不能为空字符串", nameof(value));
    
    if (value.Length > 100)
        throw new ArgumentOutOfRangeException(nameof(value), "值长度不能超过100");
}

七、总结 #

异常处理要点:

要点 说明
Exception 所有异常的基类
SystemException 系统异常
ApplicationException 应用异常
IOException I/O异常
Message 异常消息
StackTrace 调用堆栈

下一步,让我们学习try-catch语句!

最后更新:2026-03-26