Como posso obter o número da linha que gerou uma exceção?

198

Em um catchbloco, como posso obter o número da linha que lançou uma exceção?

MBZ
fonte
em tempo de execução, não há código fonte. Para que essa linha não será usada? no momento da depuração, o IDE mostra claramente a linha que gera uma exceção.
Ankitjaininfo
possível duplicação do tratamento
Fredrik Mörk
1
possível duplicata Mostrar número da linha no tratamento de exceção
Thom Smith
@ankitjaininfo não é útil se não houver IDE!
Michael
Isso responde sua pergunta? Mostrar número da linha no tratamento de exceções
Liam

Respostas:

280

Se você precisar do número da linha para mais do que apenas o rastreamento de pilha formatado obtido de Exception.StackTrace, poderá usar a classe StackTrace :

try
{
    throw new Exception();
}
catch (Exception ex)
{
    // Get stack trace for the exception with source file information
    var st = new StackTrace(ex, true);
    // Get the top stack frame
    var frame = st.GetFrame(0);
    // Get the line number from the stack frame
    var line = frame.GetFileLineNumber();
}

Observe que isso só funcionará se houver um arquivo pdb disponível para o assembly.

Quartermeister
fonte
2
? (Novo StackTrace (ex, True)). GetFrame (0) .GetFileLineNumber () para VB linha única a partir da janela imediata.
18712 Jonathan
34
C # one liner:int line = (new StackTrace(ex, true)).GetFrame(0).GetFileLineNumber();
gunwin
17
Isso sempre retorna 0 para mim. Isso é causado por não ter um arquivo pdb? O que é e como obtê-lo? (Estou usando ASP.net)
Brabbeldas
17
Por que você está usando GetFrame (0)? Eu acho que você deveria estar usando GetFrame (FrameCount-1).
Dewald Swanepoel
9
Eu achei a sugestão do @DewaldSwanepoel de usar GetFrame(st.FrameCount-1)muito mais confiável.
Brad Martin
75

De maneira simples, use a Exception.ToString()função, ela retornará a linha após a descrição da exceção.

Você também pode verificar o banco de dados de depuração do programa, pois ele contém informações / logs de depuração sobre todo o aplicativo.

SimpleButPerfect
fonte
Bem MSDN pensa diferente, que "Cria e retorna uma representação de seqüência a exceção atual": msdn.microsoft.com/en-us/library/...
Prokurors
Você obtém algo semelhante a:System.Exception: Test at Tests.Controllers.HomeController.About() in c:\Users\MatthewB\Documents\Visual Studio 2013\Projects\Tests\Tests\Controllers\HomeController.cs:line 22
Professor de programação
3
Essa deve ser a resposta aceita. Eu sempre fui ao ex.message e me perguntei por que o estúpido VB.net não é capaz de obter as mesmas informações que em Java.
Matthis Kohli
3
É uma loucura que essa resposta não tenha mais votos positivos. Isso é simples, funciona de maneira confiável e não vem com as advertências do PDB.
Nick Painter
9
Exception.Messageestá morto para mim. Nunca mais.
Reintegrar Monica Cellio
27

Se você não possui o .PBOarquivo:

C #

public int GetLineNumber(Exception ex)
{
    var lineNumber = 0;
    const string lineSearch = ":line ";
    var index = ex.StackTrace.LastIndexOf(lineSearch);
    if (index != -1)
    {
        var lineNumberText = ex.StackTrace.Substring(index + lineSearch.Length);
        if (int.TryParse(lineNumberText, out lineNumber))
        {
        }
    }
    return lineNumber;
}

Vb.net

Public Function GetLineNumber(ByVal ex As Exception)
    Dim lineNumber As Int32 = 0
    Const lineSearch As String = ":line "
    Dim index = ex.StackTrace.LastIndexOf(lineSearch)
    If index <> -1 Then
        Dim lineNumberText = ex.StackTrace.Substring(index + lineSearch.Length)
        If Int32.TryParse(lineNumberText, lineNumber) Then
        End If
    End If
    Return lineNumber
End Function

Ou como uma extensão na classe Exception

public static class MyExtensions
{
    public static int LineNumber(this Exception ex)
    {
        var lineNumber = 0;
        const string lineSearch = ":line ";
        var index = ex.StackTrace.LastIndexOf(lineSearch);
        if (index != -1)
        {
            var lineNumberText = ex.StackTrace.Substring(index + lineSearch.Length);
            if (int.TryParse(lineNumberText, out lineNumber))
            {
            }
        }
        return lineNumber;
    }
}   
radbyx
fonte
8
Infelizmente, não funcionará no sistema operacional não inglês (a palavra "linha" depende da localidade).
Ivan Kochurkin
2
@KvanTTT Você pode usar Regex.Matchcom :[^ ]+ (\d+)o mesmo efeito.
precisa
Esta resposta não funciona para mim, pois o ex.StackTrace não tem :line e eu não tenho o arquivo PDB.
Chimpanzé guerreiro
18

Você pode incluir .PDBarquivos de símbolos associados à montagem que contêm informações de metadados e, quando uma exceção é lançada, ela contém informações completas no rastreamento de pilha de onde essa exceção se originou. Ele conterá os números de linha de cada método na pilha.

Darin Dimitrov
fonte
Como se poderia incluir um PDB? Existe uma maneira de agrupar o PDB no aplicativo / registrá-lo no GAC?
Jacob Persi
7

Funciona:

var LineNumber = new StackTrace(ex, True).GetFrame(0).GetFileLineNumber();
Thirisangu Ramanathan
fonte
E as exceções não tratadas? como UnhandledExceptionEventArgsobjeto
Yousha Aleayoub 20/11/19
6

Confira este

StackTrace st = new StackTrace(ex, true);
//Get the first stack frame
StackFrame frame = st.GetFrame(0);

//Get the file name
string fileName = frame.GetFileName();

//Get the method name
string methodName = frame.GetMethod().Name;

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

//Get the column number
int col = frame.GetFileColumnNumber();
Ram Maurya
fonte
1

Atualize para a resposta

    // Get stack trace for the exception with source file information
    var st = new StackTrace(ex, true);
    // Get the top stack frame
    var frame = st.GetFrame(st.FrameCount-1);
    // Get the line number from the stack frame
    var line = frame.GetFileLineNumber();
Sean Fleming
fonte
1

Tentei usar a solução By @ davy-c, mas tinha uma exceção "System.FormatException: 'String de entrada não estava no formato correto.'", Isso ocorreu porque ainda havia texto após o número da linha, modifiquei o código postou e veio com:

int line = Convert.ToInt32(objErr.ToString().Substring(objErr.ToString().IndexOf("line")).Substring(0, objErr.ToString().Substring(objErr.ToString().IndexOf("line")).ToString().IndexOf("\r\n")).Replace("line ", ""));

Isso funciona para mim no VS2017 C #.

Joseph Michael
fonte
0

Método de Extensão

static class ExceptionHelpers
{
    public static int LineNumber(this Exception ex)
    {
        int n;
        int i = ex.StackTrace.LastIndexOf(" ");
        if (i > -1)
        {
            string s = ex.StackTrace.Substring(i + 1);
            if (int.TryParse(s, out n))
                return n;
        }
        return -1;
    }
}

Uso

try
{
    throw new Exception("A new error happened");
}
catch (Exception ex)
{
    //If error in exception LineNumber() will be -1
    System.Diagnostics.Debug.WriteLine("[" + ex.LineNumber() + "] " + ex.Message);
}
Arvo Bowen
fonte
0

Trabalhando para mim:

var st = new StackTrace(e, true);

// Get the bottom stack frame
var frame = st.GetFrame(st.FrameCount - 1);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
var method = frame.GetMethod().ReflectedType.FullName;
var path = frame.GetFileName();
Shivendra Singh
fonte
0

Eu adicionei uma extensão ao Exception que retorna a linha, coluna, método, nome do arquivo e mensagem:

public static class Extensions
{
    public static string ExceptionInfo(this Exception exception)
    {

        StackFrame stackFrame = (new StackTrace(exception, true)).GetFrame(0);
        return string.Format("At line {0} column {1} in {2}: {3} {4}{3}{5}  ",
           stackFrame.GetFileLineNumber(), stackFrame.GetFileColumnNumber(),
           stackFrame.GetMethod(), Environment.NewLine, stackFrame.GetFileName(),
           exception.Message);

    }
}
vyengr
fonte
-3

No arquivo Global.resx, há um evento chamado Application_Error

ele é acionado sempre que ocorre um erro, você pode facilmente obter qualquer informação sobre o erro e enviá-lo para um e-mail de rastreamento de bug.

Também acho que tudo o que você precisa fazer é compilar o global.resx e adicionar suas DLLs (2 DLLs) à sua pasta bin e ele funcionará!

Khaled
fonte