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

Posted

技术标签:

【中文标题】C# - 调用异常时如何获取类名和行号【英文标题】:C# - How to get Class Name and Line Number when an Exception is called 【发布时间】:2011-08-09 10:36:50 【问题描述】:

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

到目前为止,我有这段代码,它将类名和行号放在一起(例如:DatabaseHandler.cs:line 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

我想要的是例如:“类:Logging.cs,行:57”

谢谢, 瑞恩

【问题讨论】:

它对我有用,但是在做了一些调整之后(我使用的是 Compact Framework 3.9): - Frame.GetFileLineNumber 运行但总是导致异常。我删除了它。 - 所考虑的框架级别取决于您的调用堆栈。就我而言,我必须考虑 GetFrame(1),因为我必须绕过对 log() 函数的调用 【参考方案1】:

你可以这样做

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());

【讨论】:

我想,你没有 Oracle.DataAccess.Client 的源文件或者是 RELEASE 版本的 /OPTIMIZE 选项。因此,您无法从中获得任何进一步的信息。 你知道吗?这是一个例子。【参考方案2】:

System.Environment.StackTrace。任何时候都有用,而不仅仅是在例外情况下。不过可能需要一些字符串操作;

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

【讨论】:

我仍然不确定如何使用 Environment.StackTrace 获取课程,请您提供一个获取课程的示例 你是指具体的实例吗?如果是这样,我认为这是不可能的。相信我,我已经试过了。如果您指的是类型,那么您可以在StackFrame 上使用GetMethod().DeclaringType 方法。 @Flnn1179 - 没关系,感谢第二篇文章,我知道你想说什么,请查看上面的更新 2。我目前正在测试它,因为我的代码的其他部分出现了一些错误。 @Flnn1179 - 它并没有像我预期的那样工作,有没有更好的方法?查看我的输出+代码更新【参考方案3】:

我正在使用以下 class DebugE 来跟踪异常并记录应用程序中的内容:它输出 Thread# DateTime、ClassName.MethodName、Line & Col numbers 和异常消息。

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"); 它将返回相同但没有行号和列号。 请注意,对于生产应用程序,我总是会系统地调用“更简单”的调用:void debug(string methodName, exception e)。 这是因为上述“更好”的解决方案并不总是向我返回正确的方法信息。如果我的猜测是正确的,那么如果您的异常发生在没有try catch 的方法中,但被另一个确实有“try catch”的方法调用,就会出现这种情况。如果这是唯一的原因,您可以说“我将添加适当的 try catch”。问题是在现实生活中你会遇到一个真正的问题,一个需要分析的真实日志。当您注意到不相关或不充分的方法信息时,您没有机会返回您的代码,添加 try/catch 并快速重现异常。您只是最终缺少要处理的信息... 当前改进的方法深入挖掘了几帧以尝试解决这个问题并在这些特殊情况下检索类、行和列,它可能看起来像这样):[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

【讨论】:

要将 Trace 打印到文件中,请将其添加到您的配置中:&lt;system.diagnostics&gt; &lt;trace autoflush="true"&gt; &lt;listeners&gt; &lt;add name="textListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log" /&gt; &lt;remove name="Default" /&gt; &lt;/listeners&gt; &lt;/trace&gt; &lt;/system.diagnostics&gt;

以上是关于C# - 调用异常时如何获取类名和行号的主要内容,如果未能解决你的问题,请参考以下文章

Android获取Java类名/文件名/方法名/行号

如何在 Linux 上的 .NET 6 中抛出异常的 StackTrace 中获取行号

如何在OnExceptionAsync c#中获取引发异常的方法名称[重复]

调用render()时如何获取Django模板错误的文件名和行号?

C#反射执行方法返回List,怎么获取List

如何获取 Python 中发生异常或错误的行号?