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

C#-调用异常时如何获取类名和行号,c#,asp.net,C#,Asp.net,我需要两个方法,一个用于获取调用异常的类,另一个用于获取调用异常的行号 到目前为止,我已经有了这段代码,它将类名和行号放在一起(例如:DatabaseHandler.cs:Line 70): 这是在特定数据库异常时返回的内容。触发时没有行号或类名。我怎么能得到这个 Error was found at Class: Oracle.DataAccess.Client.OracleException. Line Number: 0 我想要的是例如:“Class:Loggi

我需要两个方法,一个用于获取调用异常的类,另一个用于获取调用异常的行号

到目前为止,我已经有了这段代码,它将类名和行号放在一起(例如:DatabaseHandler.cs:Line 70):

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

    Error was found at Class: Oracle.DataAccess.Client.OracleException.     
    Line Number: 0
我想要的是例如:“Class:Logging.cs,第57行”

谢谢,
Ryan

系统.环境.堆栈跟踪。任何时候都有用,而不仅仅是在例外情况下。可能需要一些字符串操作来使用它

如果您更喜欢高科技产品,可以使用
System.Diagnostics.StackFrame
;查看对象浏览器的全部详细信息,但它有查找文件名、行号和列号等的方法。

您可以这样做

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

我正在使用以下
类DebugE
跟踪应用程序中的异常并记录内容:
它输出线程#DateTime、ClassName.MethodName、行和列编号以及异常消息

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") + "] "; }
    }
}
}
要将其用于普通日志记录,请调用
DebugE.d(“一些文本”)
它将返回相同的,但不包含行号和列号。

请注意,对于生产应用程序我总是系统地调用一个“更简单”的调用:
无效调试(string methodName,异常e)

这是因为上面的“更好”解决方案并不总是向我返回正确的方法信息。如果我的猜测是正确的,那么如果您的异常发生在一个方法中,该方法没有
try-catch
,但被另一个具有“try-catch”的方法调用,则会出现这种情况。如果这是唯一的原因,你可以说“我会添加适当的尝试捕捉”。问题是,在现实生活中,你会遇到一个真正的问题,一个真正的日志需要分析。当您注意到不相关或不充分的方法信息时,您没有机会返回代码,添加try/catch并快速复制异常。您只需处理缺少的信息就可以了… 当前改进的方法深入挖掘了几个帧,试图绕过这个问题,并在这些特殊情况下检索类、行和列。它可能看起来像这样(第三帧上的跟踪实际上返回了一个有效的名称和行号)
[1-21/11 14:37:50.424914]异常:System.Threading.Tasks.Task.Delay,Ln 0列0:该值需要以毫秒为单位转换为-1(表示无限超时)、0或小于或等于Int32.MaxValue的正整数。
参数名称:延迟
[1-21/11 14:37:50.425914]异常:System.Threading.Tasks.Task.Delay,Ln 0列0:该值需要以毫秒为单位转换为-1(表示无限超时)、0或小于或等于Int32.MaxValue的正整数。
参数名称:延迟
[1-21/11 14:37:50.426415]异常:ScheduleAction.Delay,Ln 156第17列:该值需要以毫秒为单位转换为-1(表示无限超时)、0或小于或等于Int32.MaxValue的正整数。

参数名称:delay

我仍然不确定如何使用Environment.StackTrace获取类。请提供获取类的示例您是指特定实例吗?如果是这样,我认为那是不可能的。相信我,我已经试过了。如果你指的是类型,那么你可以在
StackFrame
@Flnn1179上使用
GetMethod().DeclaringType
方法-没关系,多亏了第二篇文章,我知道你想说什么,请查看上面的更新2。我目前正在测试它,因为我在代码的其他部分遇到了一些错误。@Flnn1179-它没有完全按照我的预期工作,有没有更好的方法?查看我的更新以获取输出+代码我想,您没有Oracle.DataAccess.Client的源文件,或者是带有/OPTIMIZE选项的发布版本。所以,你不能从中得到任何进一步的信息。你知道吗?这就是一个例子。要将跟踪打印到文件中,请将此添加到您的配置:
它对我有效,但在进行一些调整后(我使用的是Compact Framework 3.9):-Frame.GetFileLineNumber运行,但始终会导致异常。我把它拿走了所考虑的帧级别取决于调用堆栈。在我的例子中,我必须考虑GETFrAMP(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());
}
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);
}