50

Is there any way to retrieve the current source filename and linenumber in C# code and print that value in the console output? Like LINE and FILE in C?

Please advise.

Many thanks

domlao
  • 15,663
  • 34
  • 95
  • 134

6 Answers6

91

Anders Hejlsberg presented new API for that in BUILD keynote:

Print current file name, method name and line number

private static void Log(string text,
                        [CallerFilePath] string file = "",
                        [CallerMemberName] string member = "",
                        [CallerLineNumber] int line = 0)
{
    Console.WriteLine("{0}_{1}({2}): {3}", Path.GetFileName(file), member, line, text);
}

Test:

Log(".NET rocks!");

Output:

Program.cs_Main(11): .NET rocks!

What's going on here?

You define a method with optional parameters and decorate them with special attributes. If you call method without passing actual arguments (leave defaults) - the Framework populates them for you.

illegal-immigrant
  • 8,089
  • 9
  • 51
  • 84
  • 3
    I think the most important bit from [Caller Information](http://msdn.microsoft.com/en-us/library/hh534540) is “Caller Info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the StackTrace property for exceptions, the results aren't affected by obfuscation.”. No more reflecting to get this information! – binki Sep 17 '13 at 21:42
  • 7
    For this to work, you need to include: using System.Runtime.CompilerServices; – J. Volkya Oct 07 '13 at 21:27
  • 5
    From MSDN: Available since 4.5 – Radim Cernej Oct 28 '15 at 19:30
  • `CallerMemberName` is great, but the lack of a `CallerTypeName` attribute is both confusing and annoying. – Dai Jan 03 '21 at 00:30
38

This answer is outdated! See @taras' answer for more recent information.


No constant :(

What you can do is a lot uglier :

string currentFile = new System.Diagnostics.StackTrace(true).GetFrame(0).GetFileName(); 
int currentLine = new System.Diagnostics.StackTrace(true).GetFrame(0).GetFileLineNumber(); 

Works only when PDB files are available.

idbrii
  • 10,975
  • 5
  • 66
  • 107
user703016
  • 37,307
  • 8
  • 87
  • 112
  • I was going to post something similar, but there are issues if you try to use this code in a release build. It would work wonderfully in debug mode, though. If you need to use this, make sure you only include it in a debug build. – ZombieSheep Jun 16 '11 at 08:48
  • Oh yeah! Sorry, my mistake. :) – ZombieSheep Jun 16 '11 at 08:53
  • 1
    @ZombieSheep and @Heandel it's not so much about the if it is built in debug or release but if the PDB files are available as they are the ones that contain the debug information. PDB files are by default generated for both Debug and Release. The Debug PDB is set to contain the full debug info where as release is set to pdb-only which is still enough for a file name and and file number. – Bronumski Jun 16 '11 at 09:17
1

If you want some more internal detail, but you don't specifically need filename and line number, you can do something like this:

System.Diagnostics.Debug.Print(this.GetType().ToString() + " My Message");

This has an advantage over printing out the filename in that if you put this in a parent class, it will print out the child class name that is actually running the code.

Denise Skidmore
  • 2,286
  • 22
  • 51
1

You can use the StackTrace object from the System.Diagnostics namespace but the information will only be available if the PDB files are there.

PDB files are generated by default for both the Debug and Release builds the only difference is that Debug is setup to generate a full debug info where as the Release build is setup to only generate a pdb (full/pdb-only).

Console.WriteLine(new StackTrace(true).GetFrame(0).GetFileName());

Console.WriteLine(new StackTrace(true).GetFrame(0).GetFileLineNumber());
Bronumski
  • 14,009
  • 6
  • 49
  • 77
1

There are no constants defined for that as of now.

The .NET way of doing it is using StackTrace class.

It however works only for Debug builds. So in case you use it, you can have the code using StackTrace between

#if DEBUG
    //your StackTrace code here
#endif

You can read about using #if preprocessors for your DEBUG vs. RELEASE builds in the following Stackoverflow thread.

C# if/then directives for debug vs release

EDIT: Just in case you still need this debugging information in release builds, read the following answer on Stackoverflow:

Display lines number in Stack Trace for .NET assembly in Release mode

Community
  • 1
  • 1
Ozair Kafray
  • 13,351
  • 8
  • 59
  • 84
0

If you wanted to write your own version of Debug.Assert, then here's a more complete answer:

// CC0, Public Domain
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System;

public static class Logger {
    [Conditional("DEBUG")]  
    public static void Assert(bool condition, string msg,
            [CallerFilePath] string file = "",
            [CallerMemberName] string member = "",
            [CallerLineNumber] int line = 0
            )
    {
        // Debug.Assert opens a msg box and Trace only appears in
        // a debugger, so implement our own.
        if (!condition)
        {
            // Roughly follow style of C# error messages:
            // > ideone.cs(14,11): error CS1585: Member modifier 'static' must precede the member type and name
            Console.WriteLine($"{file}({line}): assert: in {member}: {msg}");
            // Or more precisely match style with a fake error so error-parsing tools will detect it:
            // Console.WriteLine($"{file}({line}): warning CS0: {msg}");
        }
    }
}

class Program {
    static void Main(string[] args) {
        Logger.Assert(1+1 == 4, "Why not!");
    }
}

Try it online.

idbrii
  • 10,975
  • 5
  • 66
  • 107