Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

Chained Exceptions (ข้อยกเว้นแบบโซ่) ใน C#

Chained Exceptions (ข้อยกเว้นแบบโซ่) ใน C#

Chained Exceptions คือการจับข้อยกเว้น (catch) แล้วโยนข้อยกเว้นใหม่พร้อมเก็บข้อยกเว้นเดิมไว้ใน property InnerException ช่วยให้ติดตามสาเหตุรากฐาน (root cause) ได้ครบถ้วน

โครงสร้าง InnerException


public class Exception
{
    public Exception InnerException { get; } // ข้อยกเว้นต้นทาง
    public string Message { get; }           // ข้อความข้อยกเว้นปัจจุบัน
    public string StackTrace { get; }        // Stack trace
    // ...
}

ตัวอย่าง: สร้าง Chained Exceptions


using System;

class Demo
{
    static void Main(string[] args)
    {
        try
        {
            Level1();
        }
        catch (Exception ex)
        {
            Console.WriteLine("=== Full Exception Chain ===");
            PrintExceptionChain(ex);
        }
    }

    static void Level1()
    {
        try
        {
            Level2();
        }
        catch (Exception ex)
        {
            // โยนข้อยกเว้นใหม่ พร้อมเก็บข้อยกเว้นเดิม
            throw new Exception("Level 1: Failed to process", ex);
        }
    }

    static void Level2()
    {
        try
        {
            Level3();
        }
        catch (Exception ex)
        {
            throw new Exception("Level 2: Database connection failed", ex);
        }
    }

    static void Level3()
    {
        try
        {
            Level4();
        }
        catch (Exception ex)
        {
            throw new Exception("Level 3: Query execution failed", ex);
        }
    }

    static void Level4()
    {
        // สาเหตุรากฐาน: จำลองข้อผิดพลาดจริง
        throw new InvalidOperationException("Level 4: Connection timeout");
    }

    static void PrintExceptionChain(Exception ex, int level = 0)
    {
        string indent = new string(' ', level * 4);
        Console.WriteLine($"{indent}Level {level}: {ex.GetType().Name}: {ex.Message}");
        
        if (ex.InnerException != null)
            PrintExceptionChain(ex.InnerException, level + 1);
    }
}

ผลลัพธ์


=== Full Exception Chain ===
Level 0: Exception: Level 1: Failed to process
    Level 1: Exception: Level 2: Database connection failed
        Level 2: Exception: Level 3: Query execution failed
            Level 3: InvalidOperationException: Level 4: Connection timeout

Best Practices

  1. ใช้ Exception Filters (C# 6+) เพื่อกรองก่อน rethrow
  2. อย่าโยน Exception ใหม่โดยไม่มี InnerException จะสูญเสีย context
  3. ใช้ throw; แทน throw ex; เพื่อรักษา stack trace เดิม
  4. สร้าง Custom Exception สำหรับ domain-specific errors

// ❌ ผิด - สูญเสีย stack trace
catch (Exception ex) { throw new Exception("Error", ex); }

// ✅ ถูก - เก็บ inner exception
catch (Exception ex) { throw new Exception("Error", ex); }

// ✅ ถูก - rethrow เดิม (preserve stack trace)
catch { throw; }

// ✅ C# 6+ Exception Filter
catch (SqlException ex) when (ex.Number == 1205) // Deadlock
{
    // Retry logic
}

Custom Exception แบบ Chained


[Serializable]
public class BusinessException : Exception
{
    public string ErrorCode { get; }
    
    public BusinessException(string message, string errorCode, Exception inner = null)
        : base(message, inner)
    {
        ErrorCode = errorCode;
    }
}

// ใช้งาน
throw new BusinessException("Transfer failed", "TRANSFER_001", originalEx);

การ Debug: ดู Exception Chain ใน Visual Studio

  • Exception Settings (Ctrl+Alt+E) → เลือก Break on thrown
  • Watch window: ex.InnerException, ex.StackTrace
  • ex.ToString() แสดง chain ครบใน Output Window