如果您按照您要求的方式调用它,则必须检查堆栈跟踪以找到调用方法的名称并进行大量反射以收集运行时参数信息,并且成本很高。你当然不能把电话留在原地。
您可以通过将一些冗余信息(例如当前方法名称)传递给您的跟踪内容来避免大部分成本。我已经做了类似的事情,这样我就可以使用跟踪包装器“检测”方法的主体。调用可能如下所示:
static void DoSomeMethod( )
{
Tracer.TraceRun( "DoSomeMethod", ( ) =>
{
//--> body of method...
var x = DoSomeFunction( );
} );
}
static int DoSomeFunction( )
{
return Tracer.TraceRun( "DoSomeFunction", ( ) =>
{
//--> body of method...
return 9 - DoSomeFunctionWithArgs( 3 );
} );
}
static int DoSomeFunctionWithArgs( int arg )
{
return Tracer.TraceRun( "DoSomeFunctionWithArgs", ( ) =>
{
//--> body of method...
return 1 + arg;
}, arg );
}
...运行的预期输出DoSomeMethod()
将是:
DoSomeMethod(){
DoSomeFunction(){
DoSomeFunctionWithArgs(3){
4}
5}
}
为了使这项工作,Tracer.TraceRun
被重载,以便我可以执行方法和功能:
class Tracer
{
[ThreadStatic]
private static int depth = 0;
public static void TraceRun( string name, Action method, params object[ ] args )
{
TraceStartCall( name, args );
depth++;
method( );
TraceEndCall( );
depth--;
}
public static T TraceRun<T>( string name, Func<T> function, params object[ ] args )
{
TraceStartCall( name, args );
depth++;
var results = function( );
TraceEndCall( results );
depth--;
return results;
}
private static void TraceStartCall( string functionName, params object[ ] args )
{
Trace.WriteLine
(
string.Format
(
"{0}: {1}{2}({3}){{",
Thread.CurrentThread.ManagedThreadId,
new string( ' ', depth ),
functionName,
args == null ?
string.Empty :
string.Join( ", ", Array.ConvertAll( args, i => i.ToString( ) ).ToArray( ) )
)
);
}
private static void TraceEndCall( object results = null )
{
Trace.WriteLine
(
string.Format
(
"{0}: {1}{2}}}",
Thread.CurrentThread.ManagedThreadId,
new string( ' ', depth ),
results
)
);
}
}
这段代码以廉价和简单的方式处理线程管理问题...只需输出 threadId 以便您可以查看线程如何互操作(并使用 ThreadStatic 标记 Tracer 的深度)。当我运行它时,输出看起来像这样:
10: DoSomeMethod(){
10: DoSomeFunction(){
10: DoSomeFunctionWithArgs(3){
10: 4}
10: 5}
10: }