1

I would like to print out my debug message with line number in VB.net application. I did like this,

Dim st As StackTrace
Dim sf As StackFramee
st = New StackTrace(New StackFrame(True))
sf = st.GetFrame(0)
Console.WriteLine.("Line " & sf.GetFileLineNumber())

I wanna put the snippet to a class, everytime I call logMsg method to log my message with line number in source code. But I found if I put the snippet above into a class, the line number was always same, that's the line which I new 'st'.

The function is exact same with _LINE macro in C++. Actually I am C++ programmer.

Anyway to fix this problem? thanks.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
CCC
  • 2,164
  • 8
  • 27
  • 47

3 Answers3

3

After reading the several answers I came for me to the following solution as equivalent to the C++ macro LINE

(New StackTrace(New StackFrame(True))).GetFrame(0).GetFileLineNumber())

which can be used for example as:

Console.WriteLine(String.Format("Executed on line# {0}", (New StackTrace(New StackFrame(True))).GetFrame(0).GetFileLineNumber()))
3

The code you've shown is working exactly as expected. It's printing the number of the line where you captured the stack frame. Because you've defined it in a different class, it's printing the line number of the file that contains that class.

The GetFrame method is important here. Stack frames are numbered starting at 0, which is the last stack frame pushed. So, by referring to frame 0, you are instructing the runtime to print the line number of the last stack frame that was pushed. When one method calls another, a new stack frame is created.

Instead, you need to change your method in a couple of important ways. First, you need to get the first frame that was pushed onto the stack. And second, you probably want to accept a parameter containing information about the exception that you are responding to. Try rewriting your debug method to look something like this:

Public Sub PrintCurrentLine(ByVal ex As Exception)
    Dim st As StackTrace = New StackTrace(ex)
    Dim sf As StackFrame = st.GetFrame(st.FrameCount - 1)
    Console.WriteLine("Line " & sf.GetFileLineNumber())
End Sub

Also remember that if you're running the code with optimizations enabled, things like line numbers may have changed. You always need to include the PDB file with your code, which contains debugging information that is used in situations like this. It maps the optimized code back to your original source.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • thanks very much. For my case, I have a class to maintain log message that write into a file. This is why I have to insert the line number information into the class. So this is no way to record the line number in different class, right? – CCC Apr 28 '11 at 12:46
  • @heefan: Well, there is. You could walk the entire stack, looking for the individual frame that you want. As I mentioned above, the `GetFrame` method is key, because it's what allows you to do that. Once you identify the correct frame, the `GetFileLineNumber` will do exactly what you want (except, of course, in Release mode without debug information available). The trick is getting the correct stack frame, since you're calling another method to handle debugging. The important thing to remember is that each method call creates a new stack frame. – Cody Gray - on strike Apr 28 '11 at 12:49
  • Yes, you are right. The key problem is when an application calculates the frame, that's GetFrame. Thanks for your guidance. – CCC Apr 28 '11 at 12:55
  • @heefan: I'm honestly not sure how this is different from C++. Wouldn't you have the same problem using the `_LINE` macro? If you're calling a method in a different source file, it's going to have a different line number. You have to find the right frame in the stack in order to get the correct line number. Anyway, you're welcome. – Cody Gray - on strike Apr 28 '11 at 12:57
  • @thanks Cody. In C++ it's quite useful and much easier than VB.net. We can get debug message line number and find them quickly, esp in embedded Linux environment by using __LINE__ __FILE__ and __FUNC__. I am using the system currently in my another project. BTW there is an open source log system called log4cpp. Anyway, many thanks. – CCC Apr 30 '11 at 06:45
  • @heefan: If you like log4cpp, you might also like [log4net](http://logging.apache.org/log4net/). Since both VB.NET and C# target the .NET runtime, it will work fine in either language. It's much more feature-rich than the built-in logging support, so if you need the functionality, you ought to check it out sometime. – Cody Gray - on strike Apr 30 '11 at 07:40
  • @Cody Gray. that's really cool.I will check it later. I appreciate your help. ;-) – CCC May 01 '11 at 06:55
1

The compiled assemblies will not have line numbers associated with them. This is not information that is part of the assemblies.

The information is kept in the debugging symbols file - the pdb file.

From MSDN - StackTrace class:

StackTrace information will be most informative with Debug build configurations. By default, Debug builds include debug symbols, while Release builds do not. The debug symbols contain most of the file, method name, line number, and column information used in constructing StackFrame and StackTrace objects.

Oded
  • 489,969
  • 99
  • 883
  • 1,009