Для целей отладки часто нужно узнать коллстек вызова функций, например чтобы понять место возникновения исключения. В .Net можно получить информацию о стеке вызова функций при помощи класса StackTrace.
Для удобства создадим класс, который будет хранить информацию об одном уровне в иерархии стека функций.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StackItem
{
public String Module; // модуль, в котором находится данная функция
public String ClassName; // имя класса, в котором находится данная функция
public String MethodName; // имя данной функции, из которой будет вызвана следующая функция
public String Params; // сюда положим текстовый список параметров данной функции
public String FileName; // файл, в котором находится данная функция
public Int32 Line; // строка, в которой вызвана следующая функция
public override string ToString()
{
return String.Format( "{0}.{1}({2}) {3}", ClassName, MethodName, Params,
( FileName != null ? FileName + " (" + Line.ToString() + ")" : "") );
}
}
Теперь создадим класс Dbg, который будет выполнять всю необходимую работу по получению стека функций.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class Dbg
{
// получить коллстек функций для текущего потока в виде строки
public static String GetStackString()
{
StringBuilder hStrBld = new StringBuilder();
StackItem[] stack = GetStack();
foreach( StackItem item in stack)
hStrBld.Append( item.ToString() + Environment.NewLine );
return hStrBld.ToString();
}
// получить коллстек функций для текущего потока
public static StackItem[] GetStack()
{
return GetStack( Thread.CurrentThread );
}
// получить коллстек функций для указанного потока
public static StackItem[] GetStack( Thread targetThread )
{
List< StackItem > stackList = new List< StackItem >();
StackTrace st = new StackTrace( targetThread, true );
for( Int32 i = 0; i < st.FrameCount; ++i )
{
StackItem item = GetStackItem( st.GetFrame( i ) );
if( item != null )
stackList.Add( item );
}
return stackList.ToArray();
}
// сформировать данные о фрейме стека
private static StackItem GetStackItem( StackFrame sf )
{
if( sf == null )
return null;
MethodBase method = sf.GetMethod();
if( method == null || method.ReflectedType == null )
return null;
// получить информацию о данном фрейме стека
StackItem item = new StackItem();
item.Module = method.Module.Assembly.FullName;
item.ClassName = method.ReflectedType.Name;
item.MethodName = method.Name;
item.FileName = sf.GetFileName();
item.Line = sf.GetFileLineNumber();
// получить параметры данного метода
StringBuilder params = new StringBuilder();
ParameterInfo[] paramsInfo = hMethod.GetParameters();
for( Int32 i = 0; i < paramsInfo.Length; i++ )
{
ParameterInfo currParam = paramsInfo[ i ];
szParams.Append( currParam.ParameterType.Name );
szParams.Append( " " );
szParams.Append( currParam.Name );
if( i != paramsInfo.Length - 1 )
params.Append( ", " );
}
item.Params = params.ToString();
return item;
}
}
Пользоваться данным классом очень легко. Если вам нужна строка, в которой будет записан колстек функций для текущего потока, то вам нужно вызвать функцию GetStackString. Полученную строку можно записывать в лог или вывести пользователю в отладочном сообщении.
1
2
3
String callstackStr = Dbg.GetStackString(); // получить коллстек функций для текущего потока
StackItem[] items = Dbg.GetStack(); // получение массива данных о стеке текущего потока
StackItem[] items = Dbg.GetStack( thread ); // получение массива данных о стеке указанного потока
Вот пример текста, который может быть получен функцией GetStackString, при перехвате исключения. По этому тексту можно в точности определить место в коде, где произошла ошибка.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Route.AssignVehicle( rc_Vehicle hVehicle ) Route.cs (1323)
Vehicle.Update( ) Vehicle.cs (772)
wnd_RoutePlanManager.processUpdateable( i_Updateable updateable ) RoutePlanManagerWindow.cs (89)
wnd_RoutePlanManager.objectLoaded( ModelBase obj ) RoutePlanManagerWindow.cs (123)
wnd_RoutePlanManager.objectsLoaded( List`1 objects ) RoutePlanManagerWindow.cs (184)
wnd_RoutePlanManager.onObjectsLoaded( List`1 objects ) RoutePlanManagerWindow.cs (371)
DgObjectsLoaded.Invoke( List`1 objects )
ModelController.DoObjectsLoaded( List`1 objects ) ModelController.cs (157)
Vehicle.<loadByEnterprises>b__b( DataTable res ) Vehicle.cs (1871)
<>c__DisplayClassd.<beginQuery>b__9( DataTable res ) MultiDbi.cs (173)
<>c__DisplayClass4.<beginQuery>b__3( ) asdbi.cs (863)
ThreadManager.ExecTask( TaskQueue queue, Int32 taskId ) ThreadManager.cs (603)
ThreadManager.ThreadWorker( Object parameter ) ThreadManager.cs (583)
ThreadHelper.ThreadStart_Context( Object state )
ExecutionContext.Run( ExecutionContext executionContext, ContextCallback callback, Object state )
ThreadHelper.ThreadStart( Object obj )