C# - 调用异常时如何获取类名和行号

时间:2011-08-09 10:36:51

标签: c# asp.net

我需要两个方法,一个用于从调用异常的位置获取Class,另一个用于获取调用异常的行号。

到目前为止,我有这个代码,它将类名和行号一起给我(例如:DatabaseHandler.cs:第70行):

    private string GetClassAndLine()
    {
        string tempName = e.GetBaseException().ToString();
        int tempPosition = 0;
        int length = tempName.Length;
        for (int i = 0; i < length; i++)
        {
            if (tempName.ElementAt(i).Equals('\\'))
            {
                tempPosition = i + 1;
            }
        }
        return tempName.Substring(tempPosition, length - tempPosition);
    }

因此,如果您有任何想法我可以单独获得它们,那将会有很大的帮助。然后将它们传递到Oracle以存储发生的任何异常。

更新2:

我正在测试此代码,正如一些人所建议的那样:

        private string GetClassName()
    {
        System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(e, true); 
        return trace.GetFrame(0).GetMethod().ReflectedType.FullName;
    }

    private int GetLineNumber()
    {
        System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(e, true); 
        return trace.GetFrame(0).GetFileLineNumber();
    }

这是在特定数据库异常时返回的内容。没有行号被触发的行号或类名。我怎么能得到它?

    Error was found at Class: Oracle.DataAccess.Client.OracleException.     
    Line Number: 0

我想要的是例如:“Class:Logging.cs,Line:57”

谢谢, 莱恩

3 个答案:

答案 0 :(得分:14)

你可以这样做

try
{
    // Some code that can cause an exception.

    throw new Exception("An error has happened");
}
catch (Exception ex)
{
    System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);

    Console.WriteLine(trace.GetFrame(0).GetMethod().ReflectedType.FullName);
    Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
    Console.WriteLine("Column: " + trace.GetFrame(0).GetFileColumnNumber());
}

答案 1 :(得分:3)

System.Environment.StackTrace。随时都有用,不仅仅是例外。可能需要使用它来进行一些字符串操作;

如果您喜欢更高科技的东西,可以使用System.Diagnostics.StackFrame;检查对象浏览器以获取完整的详细信息,但它有查找文件名,行号和列号等的方法。

答案 2 :(得分:1)

我使用以下class DebugE来跟踪异常并记录应用程序中的内容:
它输出Thread#DateTime, ClassName.MethodName,Line&amp;列号和异常消息。

using System;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Text.RegularExpressions;
namespace YourApp
{
class DebugE
{
    public static void d(Exception e)
    {
        try
        {
            MethodBase site = e.TargetSite;//Get the methodname from the exception.
            string methodName = site == null ? "" : site.Name;//avoid null ref if it's null.
            methodName = ExtractBracketed(methodName);

            StackTrace stkTrace = new System.Diagnostics.StackTrace(e, true);
            for (int i = 0; i < 3; i++)
            {
                //In most cases GetFrame(0) will contain valid information, but not always. That's why a small loop is needed. 
                var frame = stkTrace.GetFrame(i);
                int lineNum = frame.GetFileLineNumber();//get the line and column numbers
                int colNum = frame.GetFileColumnNumber();
                string className = ExtractBracketed(frame.GetMethod().ReflectedType.FullName);
                Trace.WriteLine(ThreadAndDateInfo + "Exception: " + className + "." + methodName + ", Ln " + lineNum + " Col " + colNum + ": " + e.Message);
                if (lineNum + colNum > 0)
                    break; //exit the for loop if you have valid info. If not, try going up one frame...
            }

        }
        catch (Exception ee)
        {
            //Avoid any situation that the Trace is what crashes you application. While trace can log to a file. Console normally not output to the same place.
            Console.WriteLine("Tracing exception in d(Exception e)" + ee.Message);
        }
    }
    public static void d(string str)
    {
        try
        {
            StackFrame frame = new StackFrame(1);
            var method = frame.GetMethod();
            string name = ExtractBracketed(method.Name);//extract the content that is inside <brackets> the rest is irrelevant 

            Trace.WriteLine(ThreadAndDateInfo + method.DeclaringType + "." + name + ": " + str);
        }
        catch (Exception e)
        {
            Console.WriteLine("Tracing exception in d(string str)" + e.Message);
        }
    }

    private static string ExtractBracketed(string str)
    {
        string s;
        if (str.IndexOf('<') > -1) //using the Regex when the string does not contain <brackets> returns an empty string.
            s = Regex.Match(str, @"\<([^>]*)\>").Groups[1].Value;
        else
            s = str; 
        if (s == "")
            return  "'Emtpy'"; //for log visibility we want to know if something it's empty.
        else
            return s;

    }

    public static string ThreadAndDateInfo
    {
        //returns thread number and precise date and time.
        get { return "[" + Thread.CurrentThread.ManagedThreadId + " - " + DateTime.Now.ToString("dd/MM HH:mm:ss.ffffff") + "] "; }
    }
}
}

从应用程序的任何位置致电:

catch (Exception e) 
{
    DebugE.d(e);
}

要将其用于普通记录,请拨打DebugE.d("some text");
它将返回相同但没有行号和列号。

请注意用于生产应用程序我总是调用&#34;更简单&#34;系统地致电:
void debug(string methodName, exception e)

这是因为&#34;更好&#34;上面的解决方案并不总是向我提供正确的方法信息。如果我的猜测是正确的,如果你的异常发生在一个没有try catch的方法中,但是被另一个确实有一个&#39; try catch&#39;的方法调用的情况就是这种情况。如果这是唯一的原因,你可以说&#34;我将添加适当的试试捕获&#34;。问题是,在现实生活中,你会遇到一个真正的问题,一个真正的分析日志。当您发现不相关或不充分的方法信息时,您将无法返回代码,添加try / catch并快速重现异常。您只是最终会找不到要处理的信息...... 当前改进的方法挖掘了几帧深度以试图解决这个问题并在这些特殊情况下检索类,行和列它看起来像这样(第3帧上的跟踪实际上返回有效的名称和行号)
[1 - 21/11 14:37:50.424914] Exception: System.Threading.Tasks.Task.Delay, Ln 0 Col 0: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue. Parameter name: delay [1 - 21/11 14:37:50.425914] Exception: System.Threading.Tasks.Task.Delay, Ln 0 Col 0: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue. Parameter name: delay [1 - 21/11 14:37:50.426415] Exception: ScheduleAction.Delay, Ln 156 Col 17: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue. Parameter name: delay