If you called it the way you're asking for, you'd have to examine the stack trace to find the calling method's name and do a lot of reflection to collect runtime argument info, and at substantial cost. You certainly couldn't leave the calls in situ.
You can avoid most of that cost by passing somewhat redundant information (such as the current method name) to your tracing stuff. I've done something similar, so that I can "instrument" the body of a method with a tracing wrapper. Calls might look like:
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 );
}
...where the expected output of running DoSomeMethod()
would be:
DoSomeMethod(){
DoSomeFunction(){
DoSomeFunctionWithArgs(3){
4}
5}
}
To make this work, the Tracer.TraceRun
is overloaded, so that I can do methods and functions:
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
)
);
}
}
This code deals with thread-management issues the cheap-and-easy way...by just outputting the threadId so that you can see how your threads interoperate (and marking Tracer's depth with ThreadStatic). The output looked like this when I ran it:
10: DoSomeMethod(){
10: DoSomeFunction(){
10: DoSomeFunctionWithArgs(3){
10: 4}
10: 5}
10: }