tags:

views:

55

answers:

3

We use Debug.Assert to signal problems in our code to the developer. I would like to add the line number where the error occurs but not hard code it as this could change and we would forget to update the string.

It would be handy to add the line number of the error. Any ideas?

+7  A: 

By default, Debug.Assert already contains stack trace information:

When the application runs in user-interface mode, it displays a message box that shows the call stack with file and line numbers.

Example:

alt text

If you're not seeing file names or line numbers in your assert dialogs, then the PDB files (which are generated as part of compilation) are missing or inaccessible. The PDB files contain file and line debugging information.

There is no true equivalent of C/C++'s __FILE__ and __LINE__ magic macros in C#, but if you still want this information outside of the assert dialogs, you can use the StackTrace class to get it. This requires you to have debugging information available (the PDB files mentioned above). Since you're probably using this for development, this is a safe requirement.

using System.Diagnostics;

namespace Managed
{
    class Program
    {
        static void Main(string[] args)
        {
            AssertWithCallSite(false, "Failed!");
        }

        [Conditional("DEBUG")]
        static void AssertWithCallSite(bool condition, string message)
        {
            if (!condition)
            {
                var callSite = (new StackTrace(1, true)).GetFrame(0);

                string fileName = callSite.GetFileName();
                int lineNumber = callSite.GetFileLineNumber();

                string assertMessage = string.Format(
                    "Assert at {0}:{1}:\n{2}",
                    fileName,
                    lineNumber,
                    message
                );

                Debug.Assert(false, assertMessage);
            }
        }
    }
}
Chris Schmich
+1  A: 

Have a look at Whats the equivalent of LINE and FILE in C#.

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

Be sure to check out the above article, as there are some caveats to be aware of.

Edward Leno
+1  A: 

Yes, this is possible. Take a look at StackTrace and StackFrame in the System.Diagnostics namespace.

Example

static string GetDiagnosticsInformationForCurrentFrame()
{
    StackTrace st = new StackTrace(new StackFrame(true));        
    StackFrame sf = st.GetFrame(1); // we want the frame from where this method was called

    return String.Format("File: {0}, Method: {1}, Line Number: {2}, Column Number: {3}", sf.GetFileName(), sf.GetMethod().Name, sf.GetFileLineNumber(), sf.GetFileColumnNumber());
}

...

Debug.Assert(true, "Unexpected error occurred at " + GetDiagnosticsInformationForCurrentFrame());

Edit As Chris pointed out, you cannot have a return type from a Conditional. I've changed my answer so that GetDiagnosticsInformationForCurrentFrame is always available.

Dennis Roche
`Conditional` attributes are only valid on `void` methods since the method might not even be present in the build.
Chris Schmich
@Chris: I did not know that, but yeah of course that would be the case. Thanks for pulling me up on my mistake. In that case, your answer is better solution (just up voted it).
Dennis Roche