C# 异常处理
本章将详细介绍 C# 中的异常处理机制,包括异常的概念、try-catch-finally语句、自定义异常、异常处理最佳实践等,帮助你编写更健壮和可靠的程序。
异常处理基础
什么是异常
csharp
// 异常是程序执行过程中发生的错误或意外情况
// C# 使用异常处理机制来处理运行时错误
using System;
static void ExceptionBasicsDemo()
{
Console.WriteLine("=== 异常基础演示 ===");
// 1. 常见的运行时异常
Console.WriteLine("1. 除零异常:");
try
{
int a = 10;
int b = 0;
int result = a / b; // 抛出 DivideByZeroException
Console.WriteLine($"结果: {result}");
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
// 2. 空引用异常
Console.WriteLine("\n2. 空引用异常:");
try
{
string text = null;
int length = text.Length; // 抛出 NullReferenceException
Console.WriteLine($"长度: {length}");
}
catch (NullReferenceException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
// 3. 索引超出范围异常
Console.WriteLine("\n3. 索引超出范围异常:");
try
{
int[] numbers = { 1, 2, 3 };
int value = numbers[5]; // 抛出 IndexOutOfRangeException
Console.WriteLine($"值: {value}");
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
// 4. 格式异常
Console.WriteLine("\n4. 格式异常:");
try
{
string input = "abc";
int number = int.Parse(input); // 抛出 FormatException
Console.WriteLine($"数字: {number}");
}
catch (FormatException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
// 5. 参数异常
Console.WriteLine("\n5. 参数异常:");
try
{
string text = "Hello";
string substring = text.Substring(-1, 5); // 抛出 ArgumentOutOfRangeException
Console.WriteLine($"子字符串: {substring}");
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
}try-catch-finally 语句
csharp
using System;
using System.IO;
static void TryCatchFinallyDemo()
{
Console.WriteLine("=== try-catch-finally 演示 ===");
// 基本 try-catch 结构
Console.WriteLine("1. 基本 try-catch:");
try
{
Console.Write("请输入一个数字: ");
string input = "42"; // 模拟输入
int number = int.Parse(input);
Console.WriteLine($"您输入的数字是: {number}");
}
catch (FormatException)
{
Console.WriteLine("输入格式错误,请输入有效数字");
}
catch (OverflowException)
{
Console.WriteLine("输入的数字超出范围");
}
// 多个 catch 块
Console.WriteLine("\n2. 多个 catch 块:");
try
{
ProcessArray();
}
catch (ArgumentNullException ex)
{
Console.WriteLine($"参数为空: {ex.ParamName}");
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"索引超出范围: {ex.Message}");
}
catch (Exception ex) // 捕获所有其他异常
{
Console.WriteLine($"发生未知异常: {ex.GetType().Name} - {ex.Message}");
}
// try-catch-finally 结构
Console.WriteLine("\n3. try-catch-finally:");
FileStream fileStream = null;
try
{
Console.WriteLine("尝试打开文件...");
// fileStream = new FileStream("nonexistent.txt", FileMode.Open);
throw new FileNotFoundException("模拟文件未找到");
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"文件操作异常: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"访问权限异常: {ex.Message}");
}
finally
{
// finally 块总是会执行,用于清理资源
Console.WriteLine("执行清理操作...");
fileStream?.Close();
Console.WriteLine("资源已释放");
}
// 嵌套 try-catch
Console.WriteLine("\n4. 嵌套 try-catch:");
try
{
Console.WriteLine("外层 try 块");
try
{
Console.WriteLine("内层 try 块");
throw new InvalidOperationException("内层异常");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"内层 catch: {ex.Message}");
throw new ApplicationException("外层异常", ex); // 重新抛出包装异常
}
}
catch (ApplicationException ex)
{
Console.WriteLine($"外层 catch: {ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"内部异常: {ex.InnerException.Message}");
}
}
}
static void ProcessArray()
{
int[] numbers = null;
// 模拟不同的异常情况
Random random = new Random();
int scenario = random.Next(1, 4);
switch (scenario)
{
case 1:
numbers = null;
int length = numbers.Length; // ArgumentNullException
break;
case 2:
numbers = new int[] { 1, 2, 3 };
int value = numbers[10]; // IndexOutOfRangeException
break;
case 3:
throw new NotImplementedException("功能尚未实现");
}
}异常信息和堆栈跟踪
csharp
using System;
using System.Diagnostics;
static void ExceptionInformationDemo()
{
Console.WriteLine("=== 异常信息演示 ===");
try
{
Method1();
}
catch (Exception ex)
{
Console.WriteLine("=== 异常详细信息 ===");
Console.WriteLine($"异常类型: {ex.GetType().FullName}");
Console.WriteLine($"异常消息: {ex.Message}");
Console.WriteLine($"异常源: {ex.Source}");
Console.WriteLine($"目标站点: {ex.TargetSite}");
Console.WriteLine("\n=== 堆栈跟踪 ===");
Console.WriteLine(ex.StackTrace);
// 检查内部异常
if (ex.InnerException != null)
{
Console.WriteLine("\n=== 内部异常 ===");
Console.WriteLine($"内部异常类型: {ex.InnerException.GetType().FullName}");
Console.WriteLine($"内部异常消息: {ex.InnerException.Message}");
}
// 异常数据
if (ex.Data.Count > 0)
{
Console.WriteLine("\n=== 异常数据 ===");
foreach (var key in ex.Data.Keys)
{
Console.WriteLine($"{key}: {ex.Data[key]}");
}
}
}
}
static void Method1()
{
Console.WriteLine("进入 Method1");
Method2();
}
static void Method2()
{
Console.WriteLine("进入 Method2");
Method3();
}
static void Method3()
{
Console.WriteLine("进入 Method3");
try
{
// 模拟一个复杂的异常情况
var ex = new InvalidOperationException("Method3 中发生错误");
ex.Data.Add("ErrorCode", "ERR001");
ex.Data.Add("Timestamp", DateTime.Now);
ex.Data.Add("UserId", "12345");
throw ex;
}
catch (InvalidOperationException ex)
{
// 包装异常并重新抛出
throw new ApplicationException("Method3 处理失败", ex);
}
}自定义异常
创建自定义异常类
csharp
// 自定义异常应该继承自 Exception 或其子类
// 遵循异常命名约定:以 Exception 结尾
using System;
using System.Runtime.Serialization;
// 基本自定义异常
public class BankAccountException : Exception
{
public string AccountNumber { get; }
public BankAccountException() : base() { }
public BankAccountException(string message) : base(message) { }
public BankAccountException(string message, Exception innerException)
: base(message, innerException) { }
public BankAccountException(string accountNumber, string message)
: base(message)
{
AccountNumber = accountNumber;
}
// 序列化构造函数(用于跨应用程序域传递异常)
protected BankAccountException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
AccountNumber = info.GetString(nameof(AccountNumber));
}
// 重写序列化方法
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(nameof(AccountNumber), AccountNumber);
}
}
// 具体的业务异常
public class InsufficientFundsException : BankAccountException
{
public decimal RequestedAmount { get; }
public decimal AvailableBalance { get; }
public InsufficientFundsException(string accountNumber, decimal requestedAmount, decimal availableBalance)
: base(accountNumber, $"账户 {accountNumber} 余额不足。请求金额: {requestedAmount:C}, 可用余额: {availableBalance:C}")
{
RequestedAmount = requestedAmount;
AvailableBalance = availableBalance;
}
}
public class AccountNotFoundException : BankAccountException
{
public AccountNotFoundException(string accountNumber)
: base(accountNumber, $"未找到账户: {accountNumber}")
{
}
}
public class AccountFrozenException : BankAccountException
{
public DateTime FrozenDate { get; }
public string Reason { get; }
public AccountFrozenException(string accountNumber, DateTime frozenDate, string reason)
: base(accountNumber, $"账户 {accountNumber} 已被冻结。冻结日期: {frozenDate:yyyy-MM-dd}, 原因: {reason}")
{
FrozenDate = frozenDate;
Reason = reason;
}
}
// 银行账户类
public class BankAccount
{
private string accountNumber;
private decimal balance;
private bool isFrozen;
private DateTime? frozenDate;
private string frozenReason;
public BankAccount(string accountNumber, decimal initialBalance = 0)
{
this.accountNumber = accountNumber ?? throw new ArgumentNullException(nameof(accountNumber));
this.balance = initialBalance;
this.isFrozen = false;
}
public string AccountNumber => accountNumber;
public decimal Balance => balance;
public bool IsFrozen => isFrozen;
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("存款金额必须大于零", nameof(amount));
if (isFrozen)
throw new AccountFrozenException(accountNumber, frozenDate.Value, frozenReason);
balance += amount;
Console.WriteLine($"账户 {accountNumber} 存款 {amount:C},当前余额: {balance:C}");
}
public void Withdraw(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("取款金额必须大于零", nameof(amount));
if (isFrozen)
throw new AccountFrozenException(accountNumber, frozenDate.Value, frozenReason);
if (amount > balance)
throw new InsufficientFundsException(accountNumber, amount, balance);
balance -= amount;
Console.WriteLine($"账户 {accountNumber} 取款 {amount:C},当前余额: {balance:C}");
}
public void FreezeAccount(string reason)
{
isFrozen = true;
frozenDate = DateTime.Now;
frozenReason = reason;
Console.WriteLine($"账户 {accountNumber} 已冻结,原因: {reason}");
}
public void UnfreezeAccount()
{
isFrozen = false;
frozenDate = null;
frozenReason = null;
Console.WriteLine($"账户 {accountNumber} 已解冻");
}
}
// 银行服务类
public class BankService
{
private Dictionary<string, BankAccount> accounts;
public BankService()
{
accounts = new Dictionary<string, BankAccount>();
}
public void CreateAccount(string accountNumber, decimal initialBalance = 0)
{
if (accounts.ContainsKey(accountNumber))
throw new InvalidOperationException($"账户 {accountNumber} 已存在");
accounts[accountNumber] = new BankAccount(accountNumber, initialBalance);
Console.WriteLine($"成功创建账户 {accountNumber},初始余额: {initialBalance:C}");
}
public BankAccount GetAccount(string accountNumber)
{
if (!accounts.TryGetValue(accountNumber, out BankAccount account))
throw new AccountNotFoundException(accountNumber);
return account;
}
public void Transfer(string fromAccount, string toAccount, decimal amount)
{
if (fromAccount == toAccount)
throw new ArgumentException("不能向同一账户转账");
var from = GetAccount(fromAccount);
var to = GetAccount(toAccount);
// 使用事务性操作
try
{
from.Withdraw(amount);
to.Deposit(amount);
Console.WriteLine($"转账成功: {fromAccount} -> {toAccount}, 金额: {amount:C}");
}
catch (Exception)
{
// 如果转账失败,这里可以实现回滚逻辑
throw;
}
}
}
static void CustomExceptionDemo()
{
Console.WriteLine("=== 自定义异常演示 ===");
BankService bank = new BankService();
try
{
// 创建账户
bank.CreateAccount("ACC001", 1000);
bank.CreateAccount("ACC002", 500);
var account1 = bank.GetAccount("ACC001");
var account2 = bank.GetAccount("ACC002");
// 正常操作
Console.WriteLine("\n=== 正常操作 ===");
account1.Deposit(200);
account1.Withdraw(150);
// 测试各种异常情况
Console.WriteLine("\n=== 异常情况测试 ===");
// 1. 余额不足异常
try
{
account2.Withdraw(1000);
}
catch (InsufficientFundsException ex)
{
Console.WriteLine($"余额不足: {ex.Message}");
Console.WriteLine($"请求金额: {ex.RequestedAmount:C}, 可用余额: {ex.AvailableBalance:C}");
}
// 2. 账户冻结异常
try
{
account1.FreezeAccount("可疑交易");
account1.Withdraw(100);
}
catch (AccountFrozenException ex)
{
Console.WriteLine($"账户冻结: {ex.Message}");
Console.WriteLine($"冻结日期: {ex.FrozenDate:yyyy-MM-dd HH:mm:ss}");
}
// 3. 账户未找到异常
try
{
bank.GetAccount("NONEXISTENT");
}
catch (AccountNotFoundException ex)
{
Console.WriteLine($"账户未找到: {ex.Message}");
}
// 4. 转账异常
try
{
bank.Transfer("ACC001", "ACC002", 500); // account1 已冻结
}
catch (AccountFrozenException ex)
{
Console.WriteLine($"转账失败 - 账户冻结: {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"未处理的异常: {ex.GetType().Name} - {ex.Message}");
}
}异常处理最佳实践
异常处理原则
csharp
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
// 1. 使用 using 语句自动释放资源
public class ResourceManagementExample
{
// ❌ 不好的做法
public static string ReadFileBad(string filePath)
{
FileStream stream = null;
StreamReader reader = null;
try
{
stream = new FileStream(filePath, FileMode.Open);
reader = new StreamReader(stream);
return reader.ReadToEnd();
}
catch (Exception ex)
{
Console.WriteLine($"读取文件失败: {ex.Message}");
return null;
}
finally
{
reader?.Close();
stream?.Close();
}
}
// ✅ 好的做法
public static string ReadFileGood(string filePath)
{
try
{
using (var stream = new FileStream(filePath, FileMode.Open))
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
catch (FileNotFoundException)
{
Console.WriteLine($"文件未找到: {filePath}");
return null;
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"没有访问权限: {filePath}");
return null;
}
catch (IOException ex)
{
Console.WriteLine($"IO错误: {ex.Message}");
return null;
}
}
// ✅ 更好的做法 - 使用现代API
public static async Task<string> ReadFileAsync(string filePath)
{
try
{
return await File.ReadAllTextAsync(filePath);
}
catch (FileNotFoundException)
{
Console.WriteLine($"文件未找到: {filePath}");
return null;
}
catch (Exception ex)
{
Console.WriteLine($"读取文件失败: {ex.Message}");
throw; // 重新抛出未知异常
}
}
}
// 2. 异常过滤器 (Exception Filters)
public class ExceptionFilterExample
{
public static void ProcessData(string data)
{
try
{
// 模拟数据处理
if (string.IsNullOrEmpty(data))
throw new ArgumentException("数据不能为空");
if (data.Length > 1000)
throw new ArgumentException("数据过长");
// 处理数据...
Console.WriteLine($"处理数据: {data}");
}
catch (ArgumentException ex) when (ex.Message.Contains("数据不能为空"))
{
Console.WriteLine("处理空数据异常");
// 使用默认数据
}
catch (ArgumentException ex) when (ex.Message.Contains("数据过长"))
{
Console.WriteLine("处理数据过长异常");
// 截断数据
}
catch (ArgumentException ex)
{
Console.WriteLine($"其他参数异常: {ex.Message}");
}
}
// 使用异常过滤器进行日志记录
public static bool LogException(Exception ex)
{
Console.WriteLine($"[LOG] 异常: {ex.GetType().Name} - {ex.Message}");
return false; // 返回 false 表示不处理异常,继续向上传播
}
public static void ProcessWithLogging(string data)
{
try
{
ProcessData(data);
}
catch (Exception ex) when (LogException(ex))
{
// 这个 catch 块永远不会执行,因为 LogException 返回 false
// 但异常会被记录
}
}
}
// 3. 异常重试机制
public class RetryExample
{
public static async Task<string> DownloadWithRetry(string url, int maxRetries = 3)
{
using (var client = new HttpClient())
{
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
Console.WriteLine($"尝试下载 (第 {attempt} 次): {url}");
var response = await client.GetStringAsync(url);
Console.WriteLine("下载成功");
return response;
}
catch (HttpRequestException ex) when (attempt < maxRetries)
{
Console.WriteLine($"下载失败 (第 {attempt} 次): {ex.Message}");
// 指数退避策略
int delay = (int)Math.Pow(2, attempt) * 1000; // 2^attempt 秒
Console.WriteLine($"等待 {delay}ms 后重试...");
await Task.Delay(delay);
}
catch (HttpRequestException ex) when (attempt == maxRetries)
{
Console.WriteLine($"下载最终失败: {ex.Message}");
throw new ApplicationException($"在 {maxRetries} 次尝试后下载失败", ex);
}
}
return null; // 永远不会到达这里
}
}
}
// 4. 异常聚合
public class AggregateExceptionExample
{
public static async Task ProcessMultipleTasksAsync()
{
var tasks = new List<Task>
{
Task.Run(() => throw new InvalidOperationException("任务1失败")),
Task.Run(() => throw new ArgumentException("任务2失败")),
Task.Run(() => Console.WriteLine("任务3成功")),
Task.Run(() => throw new NotImplementedException("任务4失败"))
};
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
Console.WriteLine($"捕获到异常: {ex.GetType().Name} - {ex.Message}");
// 检查是否是 AggregateException
if (ex is AggregateException aggEx)
{
Console.WriteLine($"聚合异常包含 {aggEx.InnerExceptions.Count} 个内部异常:");
foreach (var innerEx in aggEx.InnerExceptions)
{
Console.WriteLine($" - {innerEx.GetType().Name}: {innerEx.Message}");
}
// 处理特定类型的异常
aggEx.Handle(innerEx =>
{
if (innerEx is InvalidOperationException)
{
Console.WriteLine($"处理 InvalidOperationException: {innerEx.Message}");
return true; // 表示已处理
}
return false; // 表示未处理,将重新抛出
});
}
}
}
}
static async Task BestPracticesDemo()
{
Console.WriteLine("=== 异常处理最佳实践演示 ===");
// 1. 资源管理
Console.WriteLine("1. 资源管理:");
string content = ResourceManagementExample.ReadFileGood("test.txt");
// 2. 异常过滤器
Console.WriteLine("\n2. 异常过滤器:");
ExceptionFilterExample.ProcessData("");
ExceptionFilterExample.ProcessData("正常数据");
// 3. 重试机制
Console.WriteLine("\n3. 重试机制:");
try
{
// 注意:这会实际尝试网络请求,可能失败
// await RetryExample.DownloadWithRetry("https://httpstat.us/500");
Console.WriteLine("重试机制演示已跳过(避免实际网络请求)");
}
catch (Exception ex)
{
Console.WriteLine($"重试最终失败: {ex.Message}");
}
// 4. 聚合异常
Console.WriteLine("\n4. 聚合异常:");
await AggregateExceptionExample.ProcessMultipleTasksAsync();
}异常处理反模式
csharp
// 常见的异常处理错误和正确做法
public class ExceptionAntiPatterns
{
// ❌ 反模式1: 吞噬异常
public static void BadExample1()
{
try
{
// 一些可能失败的操作
int result = 10 / 0;
}
catch
{
// 什么都不做 - 这是非常糟糕的做法!
}
}
// ✅ 正确做法1: 适当处理或重新抛出
public static void GoodExample1()
{
try
{
int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
// 记录异常
Console.WriteLine($"除零错误: {ex.Message}");
// 根据情况决定是否重新抛出
throw; // 或者处理后返回默认值
}
}
// ❌ 反模式2: 捕获 Exception 而不是具体异常
public static void BadExample2(string input)
{
try
{
int number = int.Parse(input);
Console.WriteLine($"数字: {number}");
}
catch (Exception ex)
{
Console.WriteLine("发生错误"); // 信息不够具体
}
}
// ✅ 正确做法2: 捕获具体异常类型
public static void GoodExample2(string input)
{
try
{
int number = int.Parse(input);
Console.WriteLine($"数字: {number}");
}
catch (ArgumentNullException)
{
Console.WriteLine("输入不能为空");
}
catch (FormatException)
{
Console.WriteLine("输入格式不正确,请输入有效数字");
}
catch (OverflowException)
{
Console.WriteLine("输入的数字超出范围");
}
}
// ❌ 反模式3: 使用异常控制程序流程
public static int BadExample3(string[] array, string target)
{
try
{
for (int i = 0; ; i++)
{
if (array[i] == target)
return i;
}
}
catch (IndexOutOfRangeException)
{
return -1; // 使用异常来结束循环
}
}
// ✅ 正确做法3: 使用正常的控制结构
public static int GoodExample3(string[] array, string target)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == target)
return i;
}
return -1;
}
// ❌ 反模式4: 抛出 Exception 而不是具体异常
public static void BadExample4(int age)
{
if (age < 0)
throw new Exception("年龄不能为负数");
}
// ✅ 正确做法4: 抛出具体的异常类型
public static void GoodExample4(int age)
{
if (age < 0)
throw new ArgumentOutOfRangeException(nameof(age), age, "年龄不能为负数");
}
// ❌ 反模式5: 丢失原始异常信息
public static void BadExample5()
{
try
{
SomeMethodThatThrows();
}
catch (Exception ex)
{
throw new ApplicationException("操作失败"); // 丢失了原始异常
}
}
// ✅ 正确做法5: 保留原始异常信息
public static void GoodExample5()
{
try
{
SomeMethodThatThrows();
}
catch (Exception ex)
{
throw new ApplicationException("操作失败", ex); // 保留内部异常
}
}
private static void SomeMethodThatThrows()
{
throw new InvalidOperationException("原始错误");
}
}
// 异常处理工具类
public static class ExceptionHelper
{
// 安全执行操作,返回结果或默认值
public static T SafeExecute<T>(Func<T> operation, T defaultValue = default(T))
{
try
{
return operation();
}
catch (Exception ex)
{
Console.WriteLine($"操作失败: {ex.Message}");
return defaultValue;
}
}
// 安全执行操作,返回成功标志
public static bool TryExecute(Action operation, out Exception exception)
{
exception = null;
try
{
operation();
return true;
}
catch (Exception ex)
{
exception = ex;
return false;
}
}
// 重试执行操作
public static T RetryExecute<T>(Func<T> operation, int maxRetries = 3, int delayMs = 1000)
{
Exception lastException = null;
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
return operation();
}
catch (Exception ex)
{
lastException = ex;
if (attempt < maxRetries)
{
Console.WriteLine($"尝试 {attempt} 失败,{delayMs}ms 后重试: {ex.Message}");
Thread.Sleep(delayMs);
}
}
}
throw new AggregateException($"在 {maxRetries} 次尝试后操作仍然失败", lastException);
}
}
static void AntiPatternsDemo()
{
Console.WriteLine("=== 异常处理反模式演示 ===");
// 演示正确的异常处理
Console.WriteLine("1. 具体异常处理:");
ExceptionAntiPatterns.GoodExample2("abc");
ExceptionAntiPatterns.GoodExample2("123");
// 演示工具类使用
Console.WriteLine("\n2. 异常处理工具:");
// 安全执行
int result = ExceptionHelper.SafeExecute(() => int.Parse("abc"), -1);
Console.WriteLine($"安全解析结果: {result}");
// 尝试执行
bool success = ExceptionHelper.TryExecute(() =>
{
int x = 10 / 0;
}, out Exception ex);
Console.WriteLine($"执行结果: {success}");
if (!success)
{
Console.WriteLine($"异常: {ex.Message}");
}
// 重试执行
try
{
int retryResult = ExceptionHelper.RetryExecute(() =>
{
if (new Random().Next(1, 4) != 3) // 66% 失败率
throw new InvalidOperationException("随机失败");
return 42;
}, maxRetries: 3, delayMs: 500);
Console.WriteLine($"重试成功,结果: {retryResult}");
}
catch (AggregateException ex)
{
Console.WriteLine($"重试最终失败: {ex.Message}");
}
}本章小结
本章详细介绍了 C# 中的异常处理:
关键要点:
- 异常概念:程序运行时发生的错误或意外情况
- try-catch-finally:异常处理的基本语法结构
- 异常层次:所有异常都继承自 Exception 类
- 自定义异常:创建特定于业务逻辑的异常类型
- 异常信息:Message、StackTrace、InnerException 等
异常处理原则:
- 具体性:捕获具体的异常类型而不是 Exception
- 适度性:只在能够处理的地方捕获异常
- 信息保留:保留原始异常信息和堆栈跟踪
- 资源清理:使用 finally 或 using 确保资源释放
- 性能考虑:异常处理有性能开销,不应用于控制流程
最佳实践:
- 使用 using 语句自动管理资源
- 异常过滤器提供更精确的异常处理
- 实现重试机制处理临时性错误
- 避免吞噬异常或过度捕获
- 创建有意义的自定义异常类型
常见反模式:
- 空的 catch 块(吞噬异常)
- 捕获 Exception 而不是具体异常
- 使用异常控制程序流程
- 抛出 Exception 而不是具体异常类型
- 丢失原始异常信息
异常处理策略:
- 快速失败:尽早发现和报告错误
- 优雅降级:在出错时提供备选方案
- 重试机制:处理临时性错误
- 断路器模式:防止级联失败
下一步: 在下一章中,我们将学习 LINQ(语言集成查询),了解如何使用声明式语法查询和操作数据。