首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 異常處理進階(二):自訂例外、finally 保證執行、例外篩選與最佳實踐

     編輯:關於C語言

自訂例外類別

using System;
using System.Runtime.Serialization;

[Serializable]
public class TooManyItemsException : Exception
{
    public int MaxItems { get; }
    public int AttemptedItems { get; }

    public TooManyItemsException() 
        : base("項目數量超過限制") { }

    public TooManyItemsException(string message) 
        : base(message) { }

    public TooManyItemsException(string message, Exception inner) 
        : base(message, inner) { }

    // 完整建構函式:支援序列化
    protected TooManyItemsException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        MaxItems = info.GetInt32(nameof(MaxItems));
        AttemptedItems = info.GetInt32(nameof(AttemptedItems));
    }

    // 便利建構函式
    public TooManyItemsException(int max, int attempted)
        : base($"嘗試存取 {attempted} 項,上限 {max} 項")
    {
        MaxItems = max;
        AttemptedItems = attempted;
    }

    // 序列化支援
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue(nameof(MaxItems), MaxItems);
        info.AddValue(nameof(AttemptedItems), AttemptedItems);
    }
}

拋出與捕獲自訂例外

public class ExceptionTester
{
    public static void Main()
    {
        var tester = new ExceptionTester();
        try
        {
            tester.GenerateException(5);
        }
        catch (TooManyItemsException ex)
        {
            Console.WriteLine($"自訂例外:{ex.Message}");
            Console.WriteLine($"上限:{ex.MaxItems},嘗試:{ex.AttemptedItems}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"其他例外:{ex.Message}");
        }
        finally
        {
            Console.WriteLine("Finally from Main.");
        }
    }

    void GenerateException(int iterations)
    {
        int maxSize = 3;
        byte[] buffer = new byte[maxSize];
        
        using (var sw = new StreamWriter("log.txt"))
        {
            try
            {
                if (iterations > buffer.Length)
                    throw new TooManyItemsException(maxSize, iterations); // 拋出自訂例外
                
                for (byte i = 0; i < iterations; i++)
                {
                    sw.WriteLine($"Byte {i+1}: {i}");
                    buffer[i] = i;
                }
            }
            finally
            {
                Console.WriteLine("Finally from GenerateException.");
                sw.WriteLine("Close");
            }
        }
    }
}

多重 catch 區塊順序規則

try
{
    // 可能拋出多種例外
}
catch (TooManyItemsException ex)  // 最具體的優先
{
    // 處理自訂例外
}
catch (ArgumentNullException ex)  // 具體系統例外
{
    // 處理空參數
}
catch (IOException ex)            // 另一具體例外
{
    // 處理 IO
}
catch (Exception ex)              // 最基底,最後捕獲
{
    // 記錄未預期錯誤
}

finally 區塊保證執行

  • 無論 try 區塊正常結束、return、break、continue、拋出例外,**finally 都會執行**
  • 例外:Environment.FailFast、進程被殺死、無限迴圈、堆疊溢位
  • 適用場景:資源清理 (關閉檔案、釋放鎖、歸還連線池)

例外篩選器

try
{
    RiskyOperation();
}
catch (Exception ex) when (ex.Message.Contains("timeout")) // C# 6+
{
    // 僅捕獲包含 "timeout" 的例外
    HandleTimeout();
}
catch (Exception ex) when (ShouldRetry(ex)) // 可呼叫方法
{
    RetryOperation();
}
catch (Exception ex)
{
    // 其他例外
}

using 敘述:語法糖保證 Dispose

// 等同 try/finally 呼叫 Dispose()
using (var sw = new StreamWriter("file.txt"))
{
    sw.WriteLine("資料");
} // 編譯器自動產生 finally { sw.Dispose(); }

// C# 8+ using 宣告 (無大括號)
using var sw = new StreamWriter("file.txt");
sw.WriteLine("資料");
// 方法結束自動 Dispose

效能考量:避免控制流程使用例外

❌ 不好:用例外控制正常流程

try { return dict[key]; }
catch (KeyNotFoundException) { return default; }

✅ 好:用 TryGetValue / ContainsKey

if (dict.TryGetValue(key, out var value)) return value;
return default;

全域例外處理

應用類型處理事件
WinFormsApplication.ThreadException + AppDomain.CurrentDomain.UnhandledException
WPFDispatcherUnhandledException + AppDomain.CurrentDomain.UnhandledException
ASP.NET CoreUseExceptionHandler / UseDeveloperExceptionPage 中介軟體
ConsoleAppDomain.CurrentDomain.UnhandledException + TaskScheduler.UnobservedTaskException

例外設計原則

  1. 僅在**真正異常**情況拋出例外 (非預期、無法繼續)
  2. 提供有意義的 Message、InnerException、自訂屬性
  3. 繼承 Exception 而非 ApplicationException (已棄用建議)
  4. 標記 [Serializable] 支援跨應用程式域/遠端
  5. 實作序列化建構函式與 GetObjectData
  6. 避免在 finally 中拋出新例外 (會遮蔽原始例外)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved