本章目标

通过本章学习,你将掌握: - 异常处理的基本概念 - try-catch-finally语句的使用 - 异常类型和异常层次结构 - 自定义异常类型 - 异常处理的最佳实践 - 调试和日志记录 - 异常性能考虑

1. 异常处理基础

1.1 异常的概念

异常是程序执行过程中发生的错误或意外情况,会中断程序的正常执行流程。

// 基本异常处理示例
public class BasicExceptionHandling
{
    public static void DemonstrateBasicExceptions()
    {
        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. 数组越界异常
        try
        {
            int[] numbers = { 1, 2, 3 };
            Console.WriteLine(numbers[5]); // 抛出 IndexOutOfRangeException
        }
        catch (IndexOutOfRangeException ex)
        {
            Console.WriteLine($"数组越界:{ex.Message}");
        }
        
        // 3. 空引用异常
        try
        {
            string text = null;
            int length = text.Length; // 抛出 NullReferenceException
            Console.WriteLine($"长度:{length}");
        }
        catch (NullReferenceException ex)
        {
            Console.WriteLine($"空引用错误:{ex.Message}");
        }
        
        // 4. 类型转换异常
        try
        {
            object obj = "Hello";
            int number = (int)obj; // 抛出 InvalidCastException
            Console.WriteLine($"数字:{number}");
        }
        catch (InvalidCastException ex)
        {
            Console.WriteLine($"类型转换错误:{ex.Message}");
        }
        
        // 5. 格式异常
        try
        {
            string input = "abc";
            int number = int.Parse(input); // 抛出 FormatException
            Console.WriteLine($"数字:{number}");
        }
        catch (FormatException ex)
        {
            Console.WriteLine($"格式错误:{ex.Message}");
        }
    }
}

1.2 try-catch-finally语句

public class TryCatchFinallyDemo
{
    public static void DemonstrateTryCatchFinally()
    {
        Console.WriteLine("\n=== try-catch-finally 演示 ===");
        
        // 基本的 try-catch-finally
        try
        {
            Console.WriteLine("执行可能出错的代码");
            PerformRiskyOperation();
            Console.WriteLine("操作成功完成");
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"参数错误:{ex.Message}");
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine($"操作无效:{ex.Message}");
        }
        catch (Exception ex) // 捕获所有其他异常
        {
            Console.WriteLine($"未知错误:{ex.Message}");
            Console.WriteLine($"异常类型:{ex.GetType().Name}");
        }
        finally
        {
            Console.WriteLine("清理资源(无论是否发生异常都会执行)");
        }
        
        Console.WriteLine("程序继续执行");
    }
    
    private static void PerformRiskyOperation()
    {
        Random random = new Random();
        int choice = random.Next(1, 5);
        
        switch (choice)
        {
            case 1:
                throw new ArgumentException("模拟参数错误");
            case 2:
                throw new InvalidOperationException("模拟操作无效");
            case 3:
                throw new NotImplementedException("模拟功能未实现");
            case 4:
                Console.WriteLine("操作成功执行");
                break;
        }
    }
    
    // 文件操作示例
    public static void FileOperationExample()
    {
        Console.WriteLine("\n=== 文件操作异常处理 ===");
        
        string filePath = "test.txt";
        StreamWriter writer = null;
        
        try
        {
            writer = new StreamWriter(filePath);
            writer.WriteLine("Hello, World!");
            writer.WriteLine("异常处理示例");
            Console.WriteLine("文件写入成功");
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"访问被拒绝:{ex.Message}");
        }
        catch (DirectoryNotFoundException ex)
        {
            Console.WriteLine($"目录不存在:{ex.Message}");
        }
        catch (IOException ex)
        {
            Console.WriteLine($"IO错误:{ex.Message}");
        }
        finally
        {
            // 确保资源被释放
            writer?.Close();
            writer?.Dispose();
            Console.WriteLine("文件资源已释放");
        }
    }
    
    // using语句自动资源管理
    public static void UsingStatementExample()
    {
        Console.WriteLine("\n=== using语句示例 ===");
        
        try
        {
            using (var writer = new StreamWriter("test2.txt"))
            {
                writer.WriteLine("使用using语句");
                writer.WriteLine("自动资源管理");
                
                // 即使发生异常,using也会自动调用Dispose
                if (DateTime.Now.Millisecond % 2 == 0)
                {
                    throw new InvalidOperationException("模拟异常");
                }
                
                Console.WriteLine("文件写入成功");
            } // writer.Dispose() 自动调用
        }
        catch (Exception ex)
        {
            Console.WriteLine($"异常:{ex.Message}");
        }
        
        Console.WriteLine("using语句确保资源被正确释放");
    }
}

1.3 异常信息和堆栈跟踪

public class ExceptionInfoDemo
{
    public static void DemonstrateExceptionInfo()
    {
        Console.WriteLine("\n=== 异常信息演示 ===");
        
        try
        {
            Method1();
        }
        catch (Exception ex)
        {
            Console.WriteLine("=== 异常详细信息 ===");
            Console.WriteLine($"异常类型:{ex.GetType().Name}");
            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().Name}");
                Console.WriteLine($"内部异常消息:{ex.InnerException.Message}");
            }
            
            // 异常数据
            if (ex.Data.Count > 0)
            {
                Console.WriteLine("\n=== 异常数据 ===");
                foreach (DictionaryEntry entry in ex.Data)
                {
                    Console.WriteLine($"{entry.Key}: {entry.Value}");
                }
            }
        }
    }
    
    private static void Method1()
    {
        try
        {
            Method2();
        }
        catch (ArgumentException ex)
        {
            // 重新抛出异常,保留堆栈跟踪
            throw new InvalidOperationException("Method1中发生错误", ex);
        }
    }
    
    private static void Method2()
    {
        try
        {
            Method3();
        }
        catch (Exception ex)
        {
            // 添加额外信息
            ex.Data.Add("Method", "Method2");
            ex.Data.Add("Timestamp", DateTime.Now);
            throw; // 重新抛出原异常
        }
    }
    
    private static void Method3()
    {
        throw new ArgumentException("Method3中的参数错误");
    }
}

2. 异常类型和层次结构

2.1 .NET异常层次结构

public class ExceptionHierarchyDemo
{
    public static void DemonstrateExceptionHierarchy()
    {
        Console.WriteLine("\n=== 异常层次结构演示 ===");
        
        // System.Exception 是所有异常的基类
        Exception[] exceptions = {
            new Exception("基础异常"),
            new SystemException("系统异常"),
            new ApplicationException("应用程序异常"),
            new ArgumentException("参数异常"),
            new ArgumentNullException("参数为空异常"),
            new ArgumentOutOfRangeException("参数超出范围异常"),
            new InvalidOperationException("无效操作异常"),
            new NotSupportedException("不支持的操作异常"),
            new NotImplementedException("未实现异常"),
            new NullReferenceException("空引用异常"),
            new IndexOutOfRangeException("索引超出范围异常"),
            new DivideByZeroException("除零异常"),
            new OverflowException("溢出异常"),
            new FormatException("格式异常"),
            new InvalidCastException("无效转换异常"),
            new FileNotFoundException("文件未找到异常"),
            new DirectoryNotFoundException("目录未找到异常"),
            new UnauthorizedAccessException("未授权访问异常"),
            new TimeoutException("超时异常")
        };
        
        foreach (Exception ex in exceptions)
        {
            Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
            Console.WriteLine($"  基类: {ex.GetType().BaseType?.Name}");
            Console.WriteLine($"  是SystemException? {ex is SystemException}");
            Console.WriteLine($"  是ApplicationException? {ex is ApplicationException}");
            Console.WriteLine();
        }
    }
    
    // 演示异常捕获的顺序
    public static void DemonstrateCatchOrder()
    {
        Console.WriteLine("=== 异常捕获顺序演示 ===");
        
        try
        {
            ThrowSpecificException();
        }
        catch (ArgumentNullException ex) // 最具体的异常
        {
            Console.WriteLine($"捕获到ArgumentNullException: {ex.Message}");
        }
        catch (ArgumentException ex) // 较一般的异常
        {
            Console.WriteLine($"捕获到ArgumentException: {ex.Message}");
        }
        catch (SystemException ex) // 更一般的异常
        {
            Console.WriteLine($"捕获到SystemException: {ex.Message}");
        }
        catch (Exception ex) // 最一般的异常
        {
            Console.WriteLine($"捕获到Exception: {ex.Message}");
        }
    }
    
    private static void ThrowSpecificException()
    {
        Random random = new Random();
        int choice = random.Next(1, 5);
        
        switch (choice)
        {
            case 1:
                throw new ArgumentNullException("参数不能为空");
            case 2:
                throw new ArgumentException("参数无效");
            case 3:
                throw new InvalidOperationException("操作无效");
            case 4:
                throw new NotImplementedException("功能未实现");
        }
    }
}

2.2 常见异常类型详解

public class CommonExceptionsDemo
{
    // ArgumentException 系列
    public static void DemonstrateArgumentExceptions()
    {
        Console.WriteLine("\n=== ArgumentException 系列 ===");
        
        try
        {
            ValidateInput(null, -1, 150);
        }
        catch (ArgumentNullException ex)
        {
            Console.WriteLine($"ArgumentNullException: {ex.Message}");
            Console.WriteLine($"参数名: {ex.ParamName}");
        }
        catch (ArgumentOutOfRangeException ex)
        {
            Console.WriteLine($"ArgumentOutOfRangeException: {ex.Message}");
            Console.WriteLine($"参数名: {ex.ParamName}");
            Console.WriteLine($"实际值: {ex.ActualValue}");
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"ArgumentException: {ex.Message}");
            Console.WriteLine($"参数名: {ex.ParamName}");
        }
    }
    
    private static void ValidateInput(string name, int age, int score)
    {
        if (name == null)
            throw new ArgumentNullException(nameof(name), "姓名不能为空");
            
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("姓名不能为空白字符", nameof(name));
            
        if (age < 0 || age > 120)
            throw new ArgumentOutOfRangeException(nameof(age), age, "年龄必须在0-120之间");
            
        if (score < 0 || score > 100)
            throw new ArgumentOutOfRangeException(nameof(score), score, "分数必须在0-100之间");
    }
    
    // InvalidOperationException
    public static void DemonstrateInvalidOperationException()
    {
        Console.WriteLine("\n=== InvalidOperationException 演示 ===");
        
        var queue = new Queue<string>();
        
        try
        {
            // 尝试从空队列中取元素
            string item = queue.Dequeue(); // 抛出 InvalidOperationException
            Console.WriteLine($"取出元素: {item}");
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine($"InvalidOperationException: {ex.Message}");
        }
        
        // 自定义InvalidOperationException
        var account = new BankAccount(100);
        try
        {
            account.Withdraw(150); // 余额不足
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine($"银行操作错误: {ex.Message}");
        }
    }
    
    // FormatException 和转换异常
    public static void DemonstrateFormatExceptions()
    {
        Console.WriteLine("\n=== 格式和转换异常演示 ===");
        
        string[] inputs = { "123", "abc", "12.34", "", "  ", "2147483648" };
        
        foreach (string input in inputs)
        {
            try
            {
                int number = int.Parse(input);
                Console.WriteLine($"'{input}' -> {number}");
            }
            catch (FormatException ex)
            {
                Console.WriteLine($"格式错误 '{input}': {ex.Message}");
            }
            catch (OverflowException ex)
            {
                Console.WriteLine($"溢出错误 '{input}': {ex.Message}");
            }
            catch (ArgumentNullException ex)
            {
                Console.WriteLine($"空参数错误: {ex.Message}");
            }
        }
        
        // 安全转换方法
        Console.WriteLine("\n=== 安全转换方法 ===");
        foreach (string input in inputs)
        {
            if (int.TryParse(input, out int result))
            {
                Console.WriteLine($"'{input}' -> {result} (成功)");
            }
            else
            {
                Console.WriteLine($"'{input}' -> 转换失败");
            }
        }
    }
    
    // IO异常
    public static void DemonstrateIOExceptions()
    {
        Console.WriteLine("\n=== IO异常演示 ===");
        
        string[] filePaths = {
            "existing_file.txt",
            "non_existing_file.txt",
            "C:\\Windows\\System32\\protected_file.txt",
            "invalid_path\\<>|?.txt"
        };
        
        foreach (string filePath in filePaths)
        {
            try
            {
                string content = File.ReadAllText(filePath);
                Console.WriteLine($"成功读取文件: {filePath}");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine($"文件未找到: {ex.FileName}");
            }
            catch (DirectoryNotFoundException ex)
            {
                Console.WriteLine($"目录未找到: {ex.Message}");
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"访问被拒绝: {ex.Message}");
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine($"路径无效: {ex.Message}");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO错误: {ex.Message}");
            }
        }
    }
}

// 示例银行账户类
public class BankAccount
{
    private decimal balance;
    
    public decimal Balance => balance;
    
    public BankAccount(decimal initialBalance)
    {
        if (initialBalance < 0)
            throw new ArgumentOutOfRangeException(nameof(initialBalance), "初始余额不能为负数");
        balance = initialBalance;
    }
    
    public void Withdraw(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentOutOfRangeException(nameof(amount), "取款金额必须大于0");
            
        if (amount > balance)
            throw new InvalidOperationException($"余额不足。当前余额:{balance},尝试取款:{amount}");
            
        balance -= amount;
    }
    
    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentOutOfRangeException(nameof(amount), "存款金额必须大于0");
            
        balance += amount;
    }
}

3. 自定义异常类型

3.1 创建自定义异常

// 基础自定义异常
public class BusinessLogicException : Exception
{
    public string ErrorCode { get; }
    public DateTime Timestamp { get; }
    
    public BusinessLogicException() : base()
    {
        Timestamp = DateTime.Now;
    }
    
    public BusinessLogicException(string message) : base(message)
    {
        Timestamp = DateTime.Now;
    }
    
    public BusinessLogicException(string message, Exception innerException) : base(message, innerException)
    {
        Timestamp = DateTime.Now;
    }
    
    public BusinessLogicException(string errorCode, string message) : base(message)
    {
        ErrorCode = errorCode;
        Timestamp = DateTime.Now;
    }
    
    public BusinessLogicException(string errorCode, string message, Exception innerException) : base(message, innerException)
    {
        ErrorCode = errorCode;
        Timestamp = DateTime.Now;
    }
    
    public override string ToString()
    {
        return $"[{Timestamp:yyyy-MM-dd HH:mm:ss}] {ErrorCode}: {Message}\n{StackTrace}";
    }
}

// 具体的业务异常
public class InsufficientFundsException : BusinessLogicException
{
    public decimal RequestedAmount { get; }
    public decimal AvailableAmount { get; }
    
    public InsufficientFundsException(decimal requestedAmount, decimal availableAmount)
        : base("INSUFFICIENT_FUNDS", $"余额不足。请求金额:{requestedAmount},可用余额:{availableAmount}")
    {
        RequestedAmount = requestedAmount;
        AvailableAmount = availableAmount;
    }
}

public class AccountLockedException : BusinessLogicException
{
    public string AccountId { get; }
    public string LockReason { get; }
    public DateTime LockTime { get; }
    
    public AccountLockedException(string accountId, string lockReason, DateTime lockTime)
        : base("ACCOUNT_LOCKED", $"账户 {accountId} 已被锁定:{lockReason}")
    {
        AccountId = accountId;
        LockReason = lockReason;
        LockTime = lockTime;
    }
}

public class InvalidTransactionException : BusinessLogicException
{
    public string TransactionId { get; }
    public string ValidationError { get; }
    
    public InvalidTransactionException(string transactionId, string validationError)
        : base("INVALID_TRANSACTION", $"交易 {transactionId} 无效:{validationError}")
    {
        TransactionId = transactionId;
        ValidationError = validationError;
    }
}

// 配置异常
public class ConfigurationException : Exception
{
    public string ConfigurationKey { get; }
    public string ConfigurationFile { get; }
    
    public ConfigurationException(string configurationKey, string configurationFile, string message)
        : base($"配置错误 - 键:{configurationKey},文件:{configurationFile},错误:{message}")
    {
        ConfigurationKey = configurationKey;
        ConfigurationFile = configurationFile;
    }
    
    public ConfigurationException(string configurationKey, string configurationFile, string message, Exception innerException)
        : base($"配置错误 - 键:{configurationKey},文件:{configurationFile},错误:{message}", innerException)
    {
        ConfigurationKey = configurationKey;
        ConfigurationFile = configurationFile;
    }
}

// 验证异常
public class ValidationException : Exception
{
    public List<ValidationError> ValidationErrors { get; }
    
    public ValidationException(string message) : base(message)
    {
        ValidationErrors = new List<ValidationError>();
    }
    
    public ValidationException(List<ValidationError> validationErrors)
        : base($"验证失败,共{validationErrors.Count}个错误")
    {
        ValidationErrors = validationErrors;
    }
    
    public ValidationException(string fieldName, string errorMessage)
        : base($"字段 {fieldName} 验证失败:{errorMessage}")
    {
        ValidationErrors = new List<ValidationError>
        {
            new ValidationError(fieldName, errorMessage)
        };
    }
    
    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(Message);
        
        if (ValidationErrors.Any())
        {
            sb.AppendLine("验证错误详情:");
            foreach (var error in ValidationErrors)
            {
                sb.AppendLine($"  - {error.FieldName}: {error.ErrorMessage}");
            }
        }
        
        sb.AppendLine(StackTrace);
        return sb.ToString();
    }
}

public class ValidationError
{
    public string FieldName { get; }
    public string ErrorMessage { get; }
    public object AttemptedValue { get; }
    
    public ValidationError(string fieldName, string errorMessage, object attemptedValue = null)
    {
        FieldName = fieldName;
        ErrorMessage = errorMessage;
        AttemptedValue = attemptedValue;
    }
}

3.2 自定义异常使用示例

public class CustomExceptionDemo
{
    public static void DemonstrateCustomExceptions()
    {
        Console.WriteLine("\n=== 自定义异常演示 ===");
        
        var bankService = new BankService();
        
        try
        {
            // 测试余额不足异常
            bankService.Transfer("ACC001", "ACC002", 1000);
        }
        catch (InsufficientFundsException ex)
        {
            Console.WriteLine($"余额不足异常:");
            Console.WriteLine($"  错误代码:{ex.ErrorCode}");
            Console.WriteLine($"  请求金额:{ex.RequestedAmount}");
            Console.WriteLine($"  可用余额:{ex.AvailableAmount}");
            Console.WriteLine($"  时间戳:{ex.Timestamp}");
        }
        
        try
        {
            // 测试账户锁定异常
            bankService.Transfer("ACC003", "ACC002", 100);
        }
        catch (AccountLockedException ex)
        {
            Console.WriteLine($"\n账户锁定异常:");
            Console.WriteLine($"  账户ID:{ex.AccountId}");
            Console.WriteLine($"  锁定原因:{ex.LockReason}");
            Console.WriteLine($"  锁定时间:{ex.LockTime}");
        }
        
        try
        {
            // 测试验证异常
            var user = new User();
            user.SetUserInfo("", "invalid-email", -5);
        }
        catch (ValidationException ex)
        {
            Console.WriteLine($"\n验证异常:");
            Console.WriteLine(ex.ToString());
        }
        
        try
        {
            // 测试配置异常
            var configService = new ConfigurationService();
            configService.LoadConfiguration();
        }
        catch (ConfigurationException ex)
        {
            Console.WriteLine($"\n配置异常:");
            Console.WriteLine($"  配置键:{ex.ConfigurationKey}");
            Console.WriteLine($"  配置文件:{ex.ConfigurationFile}");
            Console.WriteLine($"  错误信息:{ex.Message}");
        }
    }
}

// 银行服务示例
public class BankService
{
    private Dictionary<string, BankAccountInfo> accounts;
    
    public BankService()
    {
        accounts = new Dictionary<string, BankAccountInfo>
        {
            { "ACC001", new BankAccountInfo("ACC001", 500, false) },
            { "ACC002", new BankAccountInfo("ACC002", 1000, false) },
            { "ACC003", new BankAccountInfo("ACC003", 2000, true) }
        };
    }
    
    public void Transfer(string fromAccountId, string toAccountId, decimal amount)
    {
        if (!accounts.TryGetValue(fromAccountId, out BankAccountInfo fromAccount))
            throw new ArgumentException($"源账户不存在:{fromAccountId}");
            
        if (!accounts.TryGetValue(toAccountId, out BankAccountInfo toAccount))
            throw new ArgumentException($"目标账户不存在:{toAccountId}");
            
        if (fromAccount.IsLocked)
            throw new AccountLockedException(fromAccountId, "账户异常活动", DateTime.Now.AddHours(-2));
            
        if (toAccount.IsLocked)
            throw new AccountLockedException(toAccountId, "风险控制", DateTime.Now.AddDays(-1));
            
        if (amount <= 0)
            throw new InvalidTransactionException(Guid.NewGuid().ToString(), "转账金额必须大于0");
            
        if (fromAccount.Balance < amount)
            throw new InsufficientFundsException(amount, fromAccount.Balance);
            
        // 执行转账
        fromAccount.Balance -= amount;
        toAccount.Balance += amount;
        
        Console.WriteLine($"转账成功:{fromAccountId} -> {toAccountId},金额:{amount}");
    }
}

public class BankAccountInfo
{
    public string AccountId { get; }
    public decimal Balance { get; set; }
    public bool IsLocked { get; set; }
    
    public BankAccountInfo(string accountId, decimal balance, bool isLocked)
    {
        AccountId = accountId;
        Balance = balance;
        IsLocked = isLocked;
    }
}

// 用户类示例
public class User
{
    public string Name { get; private set; }
    public string Email { get; private set; }
    public int Age { get; private set; }
    
    public void SetUserInfo(string name, string email, int age)
    {
        var validationErrors = new List<ValidationError>();
        
        if (string.IsNullOrWhiteSpace(name))
            validationErrors.Add(new ValidationError(nameof(name), "姓名不能为空", name));
            
        if (string.IsNullOrWhiteSpace(email) || !email.Contains("@"))
            validationErrors.Add(new ValidationError(nameof(email), "邮箱格式无效", email));
            
        if (age < 0 || age > 120)
            validationErrors.Add(new ValidationError(nameof(age), "年龄必须在0-120之间", age));
            
        if (validationErrors.Any())
            throw new ValidationException(validationErrors);
            
        Name = name;
        Email = email;
        Age = age;
    }
}

// 配置服务示例
public class ConfigurationService
{
    public void LoadConfiguration()
    {
        try
        {
            // 模拟读取配置文件
            string configFile = "app.config";
            string configKey = "DatabaseConnectionString";
            
            // 模拟配置文件不存在
            throw new FileNotFoundException($"配置文件不存在:{configFile}");
        }
        catch (FileNotFoundException ex)
        {
            throw new ConfigurationException("DatabaseConnectionString", "app.config", "配置文件不存在", ex);
        }
    }
}

4. 异常处理最佳实践

4.1 异常处理原则

public class ExceptionBestPractices
{
    // 1. 具体异常优于通用异常
    public void GoodExceptionHandling(string input)
    {
        try
        {
            int number = int.Parse(input);
            ProcessNumber(number);
        }
        catch (ArgumentNullException ex)
        {
            Console.WriteLine($"输入为空:{ex.Message}");
            // 记录日志
            LogError(ex);
        }
        catch (FormatException ex)
        {
            Console.WriteLine($"格式错误:{ex.Message}");
            // 提供用户友好的错误信息
            ShowUserFriendlyMessage("请输入有效的数字");
        }
        catch (OverflowException ex)
        {
            Console.WriteLine($"数字溢出:{ex.Message}");
            ShowUserFriendlyMessage("输入的数字太大");
        }
    }
    
    // 2. 不要忽略异常
    public void BadExceptionHandling(string input)
    {
        try
        {
            int number = int.Parse(input);
            ProcessNumber(number);
        }
        catch
        {
            // 错误:忽略所有异常
        }
    }
    
    // 3. 使用using语句管理资源
    public void ProperResourceManagement()
    {
        // 好的做法
        using (var fileStream = new FileStream("data.txt", FileMode.Open))
        using (var reader = new StreamReader(fileStream))
        {
            string content = reader.ReadToEnd();
            ProcessContent(content);
        } // 自动释放资源
    }
    
    // 4. 异常链和上下文信息
    public void ProcessDataWithContext(string data)
    {
        try
        {
            ValidateData(data);
            TransformData(data);
            SaveData(data);
        }
        catch (Exception ex)
        {
            // 添加上下文信息
            var contextException = new InvalidOperationException(
                $"处理数据时发生错误。数据长度:{data?.Length ?? 0},时间:{DateTime.Now}", ex);
            
            // 添加额外信息
            contextException.Data.Add("DataLength", data?.Length ?? 0);
            contextException.Data.Add("ProcessTime", DateTime.Now);
            contextException.Data.Add("UserId", GetCurrentUserId());
            
            throw contextException;
        }
    }
    
    // 5. 异常过滤器(C# 6.0+)
    public void ExceptionFiltering()
    {
        try
        {
            PerformOperation();
        }
        catch (HttpRequestException ex) when (ex.Message.Contains("timeout"))
        {
            Console.WriteLine("处理超时异常");
            RetryOperation();
        }
        catch (HttpRequestException ex) when (ex.Message.Contains("404"))
        {
            Console.WriteLine("处理404异常");
            HandleNotFound();
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine("处理其他HTTP异常");
            LogError(ex);
        }
    }
    
    // 6. 异步方法中的异常处理
    public async Task AsyncExceptionHandling()
    {
        try
        {
            await PerformAsyncOperation();
        }
        catch (OperationCanceledException ex)
        {
            Console.WriteLine("操作被取消");
            LogError(ex);
        }
        catch (TimeoutException ex)
        {
            Console.WriteLine("操作超时");
            LogError(ex);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"异步操作失败:{ex.Message}");
            LogError(ex);
            throw; // 重新抛出以便上层处理
        }
    }
    
    // 7. 异常聚合
    public void ProcessMultipleItems(IEnumerable<string> items)
    {
        var exceptions = new List<Exception>();
        var successCount = 0;
        
        foreach (string item in items)
        {
            try
            {
                ProcessItem(item);
                successCount++;
            }
            catch (Exception ex)
            {
                exceptions.Add(new InvalidOperationException($"处理项目 '{item}' 失败", ex));
            }
        }
        
        if (exceptions.Any())
        {
            var aggregateException = new AggregateException(
                $"批量处理完成。成功:{successCount},失败:{exceptions.Count}", exceptions);
            throw aggregateException;
        }
        
        Console.WriteLine($"所有 {successCount} 个项目处理成功");
    }
    
    // 辅助方法
    private void ProcessNumber(int number) { /* 实现 */ }
    private void ProcessContent(string content) { /* 实现 */ }
    private void ValidateData(string data) { /* 实现 */ }
    private void TransformData(string data) { /* 实现 */ }
    private void SaveData(string data) { /* 实现 */ }
    private string GetCurrentUserId() => "user123";
    private void PerformOperation() { /* 实现 */ }
    private void RetryOperation() { /* 实现 */ }
    private void HandleNotFound() { /* 实现 */ }
    private async Task PerformAsyncOperation() { /* 实现 */ }
    private void ProcessItem(string item) { /* 实现 */ }
    
    private void LogError(Exception ex)
    {
        Console.WriteLine($"[ERROR] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {ex.GetType().Name}: {ex.Message}");
    }
    
    private void ShowUserFriendlyMessage(string message)
    {
        Console.WriteLine($"[用户提示] {message}");
    }
}

4.2 异常日志记录

public interface ILogger
{
    void LogError(Exception exception, string message = null);
    void LogWarning(string message);
    void LogInfo(string message);
}

public class ConsoleLogger : ILogger
{
    public void LogError(Exception exception, string message = null)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine($"[ERROR] {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        
        if (!string.IsNullOrEmpty(message))
        {
            Console.WriteLine($"Message: {message}");
        }
        
        Console.WriteLine($"Exception: {exception.GetType().Name}");
        Console.WriteLine($"Details: {exception.Message}");
        
        if (exception.InnerException != null)
        {
            Console.WriteLine($"Inner Exception: {exception.InnerException.Message}");
        }
        
        Console.WriteLine($"Stack Trace: {exception.StackTrace}");
        Console.ResetColor();
        Console.WriteLine();
    }
    
    public void LogWarning(string message)
    {
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine($"[WARNING] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
        Console.ResetColor();
    }
    
    public void LogInfo(string message)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine($"[INFO] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
        Console.ResetColor();
    }
}

public class ExceptionLoggingDemo
{
    private readonly ILogger logger;
    
    public ExceptionLoggingDemo(ILogger logger)
    {
        this.logger = logger;
    }
    
    public void DemonstrateLogging()
    {
        Console.WriteLine("\n=== 异常日志记录演示 ===");
        
        try
        {
            logger.LogInfo("开始执行危险操作");
            PerformRiskyOperation();
            logger.LogInfo("危险操作执行成功");
        }
        catch (ArgumentException ex)
        {
            logger.LogError(ex, "参数验证失败");
        }
        catch (InvalidOperationException ex)
        {
            logger.LogError(ex, "操作状态无效");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "未知错误发生");
            throw; // 重新抛出
        }
    }
    
    private void PerformRiskyOperation()
    {
        Random random = new Random();
        int choice = random.Next(1, 4);
        
        switch (choice)
        {
            case 1:
                throw new ArgumentException("参数无效");
            case 2:
                throw new InvalidOperationException("操作无效");
            case 3:
                logger.LogInfo("操作成功完成");
                break;
        }
    }
}

5. 总结

本章全面介绍了C#异常处理的核心概念:

  1. 异常处理基础:try-catch-finally语句、异常信息和堆栈跟踪
  2. 异常类型:.NET异常层次结构、常见异常类型
  3. 自定义异常:创建和使用自定义异常类型
  4. 最佳实践:异常处理原则、日志记录、资源管理

关键要点: - 使用具体的异常类型而不是通用Exception - 不要忽略异常,适当记录和处理 - 使用using语句自动管理资源 - 为异常添加上下文信息 - 合理使用异常过滤器 - 在异步方法中正确处理异常 - 实现完善的日志记录机制

下一章预告: 下一章我们将学习泛型编程,包括泛型类、泛型方法、约束和协变逆变等高级特性。