More caveats about #line

I posted here about how you can use #line in the C# compiler to associate C# code with some other source file than the one it was compiled with. This can be very useful for code generation and for “hiding” various parts of the function from the debugger.
“Josh” asked an interesting followup question here.

But what I really want to be able to do… is to insert something like
#lineNo and #methodName into C# code and have the compiler replace it with the current method name for instrumentation purposes. This would be much better than using reflection.
Maybe for Orcas?

I don’t fully understand what he’s asking, but it does bring up some interesting points.

First, you can give filename information as well as the line number, so you really can map to any random line in any random source file.  The syntax would be: #line 15 “MyFile.txt”.

Second, recall that this #line stuff just changes how the sequence points (the IL to source mapping) in the pdb are written – it doesn’t have any impact on the actual code generated or the metadata. Since the debugger uses the pdb to map from a function back to source, changing the pdb lets you have an arbitrary mapping here.

In constrast, a managed callstack uses metadata, and not PDB information, to get the function names. So the #line stuff won’t affect the function name in the callstack.
So you can use #line to have it such that when you’re stopped in function Foo(), it maps you to the source for function Bar(). However, the callstack will still be accurate and show that you’re in function Foo().
You could name your new instrumented functions like Bar_Probe() instead of Foo(), and then use #line to map to file and line number for Bar()’s source. Then the callstack would be more intuitive. Compilers can use these sort of naming conventions to try and make their code more debuggable without changing codegen. (I recall observing anonymous delegates doing this)

Comments (5)

  1. CN says:

    Wouldn’t the point of the asker be to have a string token/macro that always, at compile time, expands to the name and line of the current method?

    That would make something like a call Log(#methodname, #lineno, "Error!"); possible, and you wouldn’t have to worry about the wrong line number being listed.

    Naturally, this is more useful in settings where you can’t have or use a good IDE to hook in the debugger. (But it would maybe make it easier for users to correctly inform the developer of the relevant error message, compared to a full stack printout.)

  2. I see. Like the C++ preprocessor’s "__LINE__" and "__FILE__" macros? Yeah, I personally would like that too. It’s true that you could have some pre-processing tool inject them for you (right before C# builds), but it’s much nicer to have it in the language.

    It’s true you can use the StackTrace class to get it at runtime (see for example), but I agree that’s a total pain and has problems.

    Note that this is purely a compiler issue. Other .Net compilers (such as MC++) have this functionality.

  3. Josh says:

    Hi Mike,

    Wow and thanks, wasn’t expecting a reply… CN Got it just right though, it was actually something much simpler I was hoping for…

    public void SomeMethod()


    Logger.LogEntyIntoMethod(#MethodName, #FileName);


    Instead of maybe…

    public void SomeMethod()


    Logger.LogEntryIntoMethod("SomeMethod", "someFile.cs");


    I agree that this could be achieved using stacktraces or even reflection.GetCurrentMethod but that affects performance.

    Thanks anyway and sorry for sending you on a wild goose chase!

  4. I wrote some C# sample code to get an ISymbolReader from a managed PDB (Program Database) file and then…

  5. I mentioned in the recent dev lab that you can debug at the IL level . I demoed two ways to do this,