如何使用try-catch获取代码的错误行号?

34

我想要获取导致错误的代码行号。例如:

static void Main(string[] args)
{
    using (SqlConnection conn = new SqlConnection(bagcum))
    {
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
        conn.Open();
        int n = cmd.ExecuteNonQuery();
    }
}

我们知道代码并不起作用,它会抛出异常,所在行数为:

int n = cmd.ExecuteNonQuery();

那么如何获取使用 try-catch 代码段的行号呢?我试过使用 StackTrace 类,但它返回的行号为0:

static void Main(string[] args)
{
    try
    {
        using (SqlConnection conn = new SqlConnection(bagcum))
        {
            SqlCommand cmd = conn.CreateCommand();
            cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
            conn.Open();
            int n = cmd.ExecuteNonQuery();
        }        
    }
    catch (Exception ex)
    {
        System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);            
        Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
    }
}

输出:

Line:0

更新:
通常代码的错误行是22,所以我必须获取那个数字。

谢谢


如果您处于“RELEASE”模式下,则堆栈跟踪中的行号(等其他信息)将不再显示。最简单的方法是编译为“DEBUG”模式。如果仍然无法正常工作,请检查项目属性\高级\调试信息是否已完全启用。 - JiBéDoublevé
@JiBéDoublevé 它处于调试模式,并且是完整的调试。 - Mustafa Ekici
1
你的.pdb文件是否与其他文件在同一个目录中? - JiBéDoublevé
10个回答

25
尝试使用这个简单的技巧代替: 首先,将此(extension)类添加到您的命名空间中(必须是顶级类):
public static class ExceptionHelper
{
    public static int LineNumber(this Exception e)
    {

        int linenum = 0;
        try
        {
            //linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(":line") + 5));

            //For Localized Visual Studio ... In other languages stack trace  doesn't end with ":Line 12"
            linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(' ')));

        }


        catch
        {
            //Stack trace is not available!
        }
        return linenum;
    }
}

完成了!每当您需要时,请使用LineNumber方法:

try
{
//Do your code here
}
catch (Exception e)
{
int linenum = e.LineNumber();
}

我也遇到了这个问题。并且通过问题代码返回0。但是你的代码却返回'e)' :( 我在一个父类中管理异常。你能帮我吗? - morteza ataiy

11

尝试这个

要在StackTrace中获取行号,您需要将正确的调试信息(PDB文件)与您的dlls/exes一起使用。要生成调试信息,请设置选项 项目属性->生成->高级->调试信息

alt text

将其设置为full应该就足够了(有关其他选项的作用,请参见MSDN文档)。默认情况下,调试版本配置会生成调试信息(即PDB文件),但是也可以为发布版本配置生成调试信息。

为发布版本生成PDB可让您在不附加PDB的情况下发布代码,但如果您需要行号(甚至附加远程调试器),则可以将PDB放在dll旁边。需要注意的一点是,在发布版本中,由于编译器或JIT编译器所做的优化,行号可能不完全正确(特别是如果行号显示为0)。


8
问题在于您正在尝试获取异常第一个帧的行号:
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());

然而,异常并不是在你编写ExecuteNonQuery这一行中产生的,而是在该函数内部某个地方,可能还有多个嵌套的函数调用。因此,第一个帧(使用GetFrame(0)明确检索的)位于Microsoft的代码内部(很可能是System.Data.dll),你没有任何调试符号。

在你的函数中完整输出异常堆栈跟踪以查看我所说的:

try
{
   // your code ...
}
catch (Exception ex) 
{
   Console.WriteLine(ex);
}

除了解析堆栈跟踪(即ex.StackTrace),没有可靠的方法来获取“ExecuteNonQuery()”调用的行号。我尤其不建议尝试沿着调用ExecuteNonQuery()的路径计算堆栈帧。

然而,我想知道你需要单独的行号干什么,为什么不直接记录/打印/输出完整的堆栈跟踪呢?至少出于诊断原因,这样做更有用。


6
如果您不初始化StackTrace以包含fileinfo,则结果可能为0。 尝试这个。
try
{
    //code
}
catch (Exception e)
{
    var lineNumber = new System.Diagnostics.StackTrace(e, true).GetFrame(0).GetFileLineNumber();
}
这对我很有帮助。

4
这是一种相对简单的方法,可以从异常对象中获取大量信息:只需将以下代码添加到任何可能引发异常的方法中:
catch (Exception ex)
{
    String exDetail = String.Format(ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
    MessageBox.Show(exDetail);
}

您得到的信息通常会更具体,特别是关于问题发生的行号,比您以前看到的要详细。

您可能已经注意到String.Format()使用了一个常量,即"ExceptionFormatString"。这是一个好的做法,这样如果您想在添加上述代码到40-11个方法之后进行更改,只需在一个地方更改即可。无论如何,在这里它就是:

public static readonly String ExceptionFormatString = "Exception message: {0}{1}Exception Source: {2}{1}Exception StackTrace: {3}{1}";

愉快的调试!


4
您可以按以下方式使用 System.Diagnostics.StackTrace 类:
public void MethodName()
{
    try
    {
        throw new Exception();
    }
    catch (Exception ex)
    {
        // Get stack trace for the exception with source file information
        var trace = new StackTrace(ex, true);

        // Get the top stack frame
        var frame = trace.GetFrame(0);

        // Get the line number from the stack frame
        var line = frame.GetFileLineNumber();
    }
}

1
要获取行号,您需要将应用程序设置为调试模式或者将调试符号包括在同一文件夹中(.pdb文件)以显示行号。然后您发布的代码应该可以工作。

1
以下代码异常日志处理程序方法运行良好: 在catch中:
 catch (Exception ex)
            {
                CommonTools.vAddToLog(ex, EmpID, ErrorCodes.UnDefined);
                Response.Redirect("~/ErrorPage.aspx");
            }
AddToLog方法中:
 string _exMsgErr = string.Empty;
                var frame = oStackTrace.FrameCount > 1 ? oStackTrace.GetFrame(1) : oStackTrace.GetFrame(0);
                if (oException.GetType() == typeof(JOVALException))
                {
                    JOVALException _JOVALEx = (JOVALException)oException;
                    _exMsgErr = _JOVALEx.Message;
                }
                else
                {
                    _exMsgErr = oException.Message;
                }
                ErrorLog oError = new ErrorLog(frame.GetMethod().Name, (string)frame.GetFileName(), (int)frame.GetFileLineNumber(), sCustomErrorMessage == string.Empty ? _exMsgErr : sCustomErrorMessage, sUserID, oErrCode);
                //Cont. your code of log file
最终,XML日志文件如下所示:

Finally the xml log file looks like this :

<ErrorLog>
<MethodName>FillRolesDDLs</MethodName>
<FileName>
F:\Projects\ERP\ERP\Pages\SystemSettings\Roles.aspx.cs
</FileName>
<LineNumber>61</LineNumber>
<ErrorMesssage>
The given DataRow is not in the current DataRowCollection.
</ErrorMesssage>
<UserID>1</UserID>
<ErrCode>UnDefined</ErrCode>
<Time>15/03/2015 16:23:21.976</Time>
</ErrorLog>

0
在.NET 4.5中,您可以使用ExceptionDispatchInfo来重新抛出异常,而不是经典的throw;(确保有PDB文件,否则将不显示行号):
    static void A()
    {
        try
        {
            throw new Exception("A");
        }
        catch (Exception e)
        {
            ExceptionDispatchInfo.Capture(e).Throw();
        }
    }

来源:博客文章。 在Windows上,PDB文件不会降低性能


-1

通过使用try/catch可以抛出异常,将整个堆栈跟踪复制到字符串或字符串构建器中,参见下面的示例

try
{
    //Do some programming
}
catch(Exception ex)
{

   //Catch the exception and assign the stack trace
   StackTrace = ex;
}

输出将会是

System.IndexOutOfRangeException: Index was outside the bounds of the array.   
at Program.Run() in C:\Console Application1\Program.cs:line 37    
at Program.Main(String[] args) in C:\Console Application1\Program.cs:line 45 

第一行显示异常类型和消息。第二行显示抛出异常的文件、函数和行号。


这似乎是一个解决方案,但我想要在不解析任何输出的情况下进行询问。 - Mustafa Ekici
代码不足,我无法让 StackTrace = ex; 运行。非工作示例给负一分。 - Omzig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,