C#的StackTrace类位于System.Diagnostics命名空间下,主要用于获取当前线程的调用堆栈信息,无论是主动获取方法调用链路,还是捕获异常时提取堆栈,都可以借助这个类实现。调用堆栈会记录方法调用的先后顺序,每一层对应一个调用帧,包含方法名、所在类、文件名、行号等信息。

StackTrace类的基础用法
如果需要主动获取当前代码的调用堆栈,可以直接实例化StackTrace类,然后遍历其中的堆栈帧信息。下面的示例展示了如何获取并打印调用堆栈的每一层信息:
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
// 实例化StackTrace,默认获取当前线程的调用堆栈
StackTrace stackTrace = new StackTrace();
// 获取所有的堆栈帧
StackFrame[] frames = stackTrace.GetFrames();
Console.WriteLine("当前调用堆栈信息:");
foreach (StackFrame frame in frames)
{
// 获取方法信息
var method = frame.GetMethod();
Console.WriteLine($"方法:{method.DeclaringType.FullName}.{method.Name}");
// 获取文件名和行号,可能为null
string fileName = frame.GetFileName();
int lineNumber = frame.GetFileLineNumber();
if (!string.IsNullOrEmpty(fileName))
{
Console.WriteLine($"文件:{fileName},行号:{lineNumber}");
}
}
}
}
上面的代码中,StackTrace默认会捕获从当前调用点到线程起点的所有堆栈信息,GetFrames方法返回所有的堆栈帧数组,每个StackFrame可以提取对应的方法、文件名、行号等详细信息。
捕获异常时获取调用堆栈
当程序抛出异常时,异常对象本身已经包含了调用堆栈信息,不过也可以通过StackTrace类结合异常对象获取更完整的堆栈内容。异常对象的StackTrace属性会返回字符串形式的堆栈信息,而使用StackTrace类实例化时可以传入异常对象,获取结构化的堆栈帧:
using System;
using System.Diagnostics;
class Program
{
static void MethodA()
{
MethodB();
}
static void MethodB()
{
try
{
// 主动抛出一个异常
throw new InvalidOperationException("测试异常");
}
catch (Exception ex)
{
// 传入异常对象实例化StackTrace
StackTrace stackTrace = new StackTrace(ex);
StackFrame[] frames = stackTrace.GetFrames();
Console.WriteLine("异常调用堆栈信息:");
foreach (StackFrame frame in frames)
{
var method = frame.GetMethod();
Console.WriteLine($"方法:{method.DeclaringType.FullName}.{method.Name}");
string fileName = frame.GetFileName();
int lineNumber = frame.GetFileLineNumber();
if (!string.IsNullOrEmpty(fileName))
{
Console.WriteLine($"文件:{fileName},行号:{lineNumber}");
}
}
// 也可以直接输出异常自带的堆栈字符串
Console.WriteLine("异常自带堆栈信息:");
Console.WriteLine(ex.StackTrace);
}
}
static void Main(string[] args)
{
MethodA();
}
}
上面的示例中,MethodB抛出了异常,在catch块中通过new StackTrace(ex)可以获取到异常发生时的完整调用堆栈,从抛出异常的方法向上追溯到调用入口,方便定位问题发生的链路。
StackTrace类的常用参数说明
实例化StackTrace类时可以传入不同的参数,控制获取的堆栈范围:
- 无参构造函数:默认获取当前线程的完整调用堆栈,包含当前方法到线程起点的所有帧。
- 传入
bool needFileInfo参数:如果传入true,则会尝试捕获文件名和行号信息,需要程序包含调试符号(pdb文件),否则文件名和行号会返回null或者0。 - 传入
Exception ex参数:可以获取指定异常发生时的调用堆栈,忽略异常捕获之后的调用链路。 - 传入
int skipFrames参数:可以跳过指定数量的堆栈帧,比如传入1就会跳过当前方法的帧,从调用当前方法的上层方法开始记录。
下面的示例展示了跳过堆栈帧的用法:
using System;
using System.Diagnostics;
class Program
{
static void PrintStackTrace()
{
// 跳过1个堆栈帧,不记录PrintStackTrace方法本身
StackTrace stackTrace = new StackTrace(1, true);
StackFrame[] frames = stackTrace.GetFrames();
Console.WriteLine("跳过当前方法后的堆栈信息:");
foreach (StackFrame frame in frames)
{
var method = frame.GetMethod();
Console.WriteLine($"方法:{method.DeclaringType.FullName}.{method.Name}");
}
}
static void Main(string[] args)
{
PrintStackTrace();
}
}
注意事项
使用StackTrace类获取文件名和行号时,需要保证程序运行时有对应的pdb调试符号文件,否则无法获取到准确的文件名和行号信息。另外,在发布版本中如果进行了代码优化,可能会导致堆栈帧的顺序或者信息出现偏差,排查问题时需要留意这一点。如果需要获取异步方法的调用堆栈,需要注意异步方法的状态机可能会导致堆栈帧的结构和同步方法不同,需要结合具体的异步调用场景分析堆栈内容。
C#StackTrace异常调用堆栈调用栈修改时间:2026-06-21 13:42:35