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

C# 精準取得例外錯誤行號:StackTrace 解析與最佳實踐

     編輯:關於C語言

前言

除錯時快速定位錯誤行號能大幅縮短排查時間。C# Exception.StackTrace 包含完整呼叫堆疊,但預設輸出冗長。本文示範如何擷取關鍵行號資訊,並介紹更現代化的 CallerLineNumber 屬性與結構化日誌最佳實踐。

方法一:直接輸出 StackTrace(基礎版)

try
{
    int num = Convert.ToInt32(""); // 故意觸發 FormatException
}
catch (Exception ex)
{
    MessageBox.Show(ex.StackTrace);
}

輸出範例:

位於 System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type)
位於 System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
位於 System.Convert.ToInt32(String value)
位於 ConsoleApp.Program.Main() 位於 D:\Projects\Test\Program.cs:行 14

缺點:資訊過多、格式隨 .NET 版本/語系變化、難以程式化解析。

方法二:字串截取「行號」關鍵字(快速修補版)

catch (Exception ex)
{
    string trace = ex.StackTrace;
    int idx = trace.IndexOf("行號"); // 繁體中文環境為 "行號",簡體為 "行号"
    if (idx >= 0)
        MessageBox.Show(trace.Substring(idx));
}

僅顯示「行號 14」等關鍵片段,適合快速除錯,但相依當地語系字串,移植性差。

方法三:StackFrame 逐幀解析(標準做法)

using System.Diagnostics;

catch (Exception ex)
{
    var st = new StackTrace(ex, true); // true = 捕獲檔案行號
    var frame = st.GetFrame(0);        // 0 = 拋出例外的當前幀
    string file = frame.GetFileName();
    int line = frame.GetFileLineNumber();
    int col = frame.GetFileColumnNumber();
    string method = frame.GetMethod()?.Name;

    MessageBox.Show($"錯誤位置:{file}:{line}:{col} 方法:{method}");
}

優點:強型別、不受語系影響、可取得檔案、行、欄、方法完整資訊。需編譯為 Debug 模式 或開啟 <DebugSymbols>true</DebugSymbols> / <DebugType>full</DebugType>,Release 建構預設不包含 PDB 行號資訊。

方法四:CallerLineNumber 編譯期注入(現代最佳實踐)

using System.Runtime.CompilerServices;

public static void LogError(string message,
    [CallerFilePath] string file = "",
    [CallerLineNumber] int line = 0,
    [CallerMemberName] string member = "")
{
    Debug.WriteLine($"[{file}:{line} {member}] {message}");
}

// 使用時完全不需傳參數
try { ... }
catch (Exception ex)
{
    LogError(ex.Message); // 自動帶入呼叫端檔案、行號、方法名
}

優點:零效能損耗、Release 也能拿到行號、程式碼極乾淨。缺點:只能拿到「呼叫 LogError 那一行」,而非「例外拋出那一行」。

結構化日誌建議

生產環境建議引入 Serilog / NLog + Seq / ELK,配合 LogContext 豐富上下文:

Log.Error(ex, "轉換失敗 | Input={Input}", input);

自動附加完整 StackTrace、機器名、執行緒 ID、相關性 ID,支援全文檢索與告警。

總結對照表

方法適用場景優點缺點
ex.StackTrace 字串快速 Console 除錯零依賴冗長、語系相依、難解析
字串截取「行號」臨時修補一行程式碼極脆弱、不跨語系
StackTrace + StackFrame庫開發、需精確定位標準 API、強型別需 PDB、Release 預設無行號
CallerLineNumber日誌封裝、現代專案編譯期注入、Release 可用只能拿到呼叫端行號

建議策略

  • 開發期:StackFrame + Debug 建構即時定位。
  • 測試/生產:CallerLineNumber 封裝日誌助手 + 結構化日誌框架,確保 Release 也能追蹤。
  • 避免在 catch 區塊直接 MessageBox.Show,改用統一日誌管線,便於集中監控。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved