Wednesday, April 17, 2013

Getting Caller Information in C# without reflection (AKA: __LINE__ and __FILE__)

When writing tracing code it's very useful to know your caller. If you've used C or C++ you likely combined macro's,  __LINE__  and __FILE__ to implement this capability.

In C# 4.5 there is a better way to solve this problem. By adding attributed function parameters you can instruct the compiler to have your callers supply their calling information.  The code (full source @ bitbucket):
     public static void TraceMessage(string message,
                [CallerMemberName] string memberName = "",
                [CallerFilePath] string sourceFilePath = "",
                [CallerLineNumber] int sourceLineNumber = 0)
            Console.WriteLine("message: " + message);
            Console.WriteLine("member name: " + memberName);
            Console.WriteLine("source file path: " + sourceFilePath);
            Console.WriteLine("source line number: " + sourceLineNumber);
        static void Main(string[] args)
Which provides the output:
PS C:\hgs\ig2600_blog\CallerInformation\bin\Debug> .\CallerInformation.exe
message: Hi
member name: Main
source file path: c:\hgs\ig2600_blog\CallerInformation\Program.cs
source line number: 27
PS C:\hgs\ig2600_blog\CallerInformation\bin\Debug>

For those who like to peek behind the curtain, this feature is implemented by having the compiler add the calling information to the call site, which we see from the IL:
.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
    IL_0000: nop
    IL_0001: ldstr "Hi"
    IL_0006: ldstr "Main"
    IL_000b: ldstr "c:\\hgs\\ig2600_blog\\CallerInformation\\Program.cs"
    IL_0010: ldc.i4.s 27
    IL_0012: call void CallerInformation.Program::TraceMessage(string,  string,  string,  int32)
    IL_0017: nop
    IL_0018: ret


Andrew Helwer said...


kristy lucas said...

This code is the solution to my problem. Thanks bro! I will visit your page every often.


Kris of Metrixa Technology