Como obtenho o número da linha atual?

117

Aqui está um exemplo do que eu quero fazer:

MessageBox.Show("Error line number " + CurrentLineNumber);

No código acima de CurrentLineNumber, deve estar o número da linha no código-fonte deste trecho de código.

Como eu posso fazer isso?

MonsterMMORPG
fonte
Você não pode fazer isso de forma confiável , pois o compilador JIT pode fazer otimizações (por exemplo, código embutido), o que significa que os números das linhas estarão errados.
adrianbanks
1
Como você pode desativar a otimização se quiser, pode fazer isso com segurança.
jwg
Possível duplicata de Imprimir o nome do arquivo de origem e o número de linho em C #
Michael Freidgeim

Respostas:

175

No .NET 4.5 / C # 5, você pode fazer com que o compilador faça esse trabalho para você, escrevendo um método utilitário que usa os novos atributos do chamador:

static void SomeMethodSomewhere()
{
    ShowMessage("Boo");
}
...
static void ShowMessage(string message,
    [CallerLineNumber] int lineNumber = 0,
    [CallerMemberName] string caller = null)
{
     MessageBox.Show(message + " at line " + lineNumber + " (" + caller + ")");
}

Isso exibirá, por exemplo:

Boo na linha 39 (SomeMethodSomewhere)

Também há o [CallerFilePath]que informa o caminho do arquivo de código original.

Marc Gravell
fonte
Muito obrigado pela resposta. é possível aprender também o nome do objeto? oh, eu confundi com outra coisa. o que me pergunto é o site do asp.net 4.5. coletor de erro global. pegar o erro causado pelo nome do objeto?
MonsterMMORPG
@MonsterMMORPG não; apenas os 3 que mencionei acima
Marc Gravell
1
@MarcGravell isso requer que o ambiente de tempo de execução também seja 4.5 OU é um recurso do compilador?
kuldeep
5
C # é tão bem projetado. Isso nunca deixa de me surpreender. Obrigado Marc!
nmit026
74

Use o método StackFrame.GetFileLineNumber , por exemplo:

private static void ReportError(string message)
{
     StackFrame callStack = new StackFrame(1, true);
     MessageBox.Show("Error: " + message + ", File: " + callStack.GetFileName() 
          + ", Line: " + callStack.GetFileLineNumber());
}

Consulte a entrada do blog de Scott Hanselman para obter mais informações.

[Editar: adicionado o seguinte]

Para aqueles que usam .Net 4.5 ou posterior, considere CallerFilePath , CallerMethodName e CallerLineNumber no namespace System.Runtime.CompilerServices. Por exemplo:

public void TraceMessage(string message,
        [CallerMemberName] string callingMethod = "",
        [CallerFilePath] string callingFilePath = "",
        [CallerLineNumber] int callingFileLineNumber = 0)
{
    // Write out message
}

Os argumentos devem ser stringpara CallerMemberNamee CallerFilePathe um intpara CallerLineNumbere devem ter um valor padrão. Especificar esses atributos em parâmetros de método instrui o compilador a inserir o valor apropriado no código de chamada em tempo de compilação, o que significa que funciona por meio de ofuscação. Consulte Informações do chamador para obter mais informações.

Akton
fonte
@MonsterMMORPG Isso funciona independentemente de haver um erro ou não. A classe StackFrame está apenas olhando para o método que chama o atual sendo executado. O primeiro argumento para o construtor StackFrame é a profundidade da chamada (1) e o segundo argumento indica que as informações do arquivo são necessárias.
Akton
3
Se você estiver compilando o StackFrameexemplo no Mono , certifique-se de usar--debug em tempo de compilação e em tempo de execução
bernard paulus
StackFramenão está disponível no .NET Core. Use a resposta de Marc Gravell.
Jesse Chisholm
Usar o valor padrão = string.Emptygera um erro "O valor do parâmetro padrão para 'callingFilePath' deve ser uma constante de tempo de compilação" !
estomia
1
@stomy mudei o examp [le para usar aspas duplas ( "") em vez de string.Empty.
Akton
21

Eu prefiro um liners, então:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
iambriansreed
fonte
8
ele precisa do arquivo .pdb .. que geralmente não geramos / copiamos para o servidor de produção.
Deepak Sharma,
4

Para aqueles que precisam de uma solução de método .NET 4.0+:

using System;
using System.IO;
using System.Diagnostics;

public static void Log(string message) {
   StackFrame stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
   string fileName = stackFrame.GetFileName();
   string methodName = stackFrame.GetMethod().ToString();
   int lineNumber = stackFrame.GetFileLineNumber();

   Console.WriteLine("{0}({1}:{2})\n{3}", methodName, Path.GetFileName(fileName), lineNumber, message);
}

Como ligar:

void Test() {
   Log("Look here!");
}

Resultado:

Teste de Vazio () (FILENAME.cs: 104)

Olhe aqui!

Altere o formato Console.WriteLine como quiser!

Jared Burrows
fonte
3
não funcionará em todos os casos .. ele precisa sempre do arquivo .pdb, que geralmente não geramos / copiamos para o servidor de produção. tente com o atributo Caller * do C # 5.0.
Deepak Sharma,
2
Se, em vez disso, você usar isto: System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));então você pode clicar na linha na janela de saída e ser levado para essa linha na fonte.
Jesse Chisholm
3

Se estiver em um bloco try catch, use-o.

try
{
    //Do something
}
catch (Exception ex)
{
    System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
    Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}
Nate-Wilkins
fonte
1

No .NET 4.5, você pode obter o número da linha criando a função:

static int LineNumber([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
    return lineNumber; 
}

Então, cada vez que você ligar, LineNumber()você terá a linha atual. Isso tem a vantagem sobre qualquer solução que usa o StackTrace de que deve funcionar tanto na depuração quanto na liberação.

Então, pegando a solicitação original do que é necessário, ele se tornaria:

MessageBox.Show("Error enter code here line number " + LineNumber());

Isso se baseia na excelente resposta de Marc Gravell.

Brian Cryer
fonte
Isso não retorna o número da linha correto. Tenho que subtrair 191 para acertar por algum motivo.
Daniel
Interessante. Funciona bem aqui para mim. Você tem números de link ativados no IDE? Se você chamar essa função de locais diferentes no arquivo, ainda terá que subtrair 191? Isso pode ser um bug do compilador (improvável, mas possível) ou um bloco reduzido em sua página (embora isso não deva evitar que os números das linhas sejam corretos, pode explicar a diferença se você estiver contando em vez de procurar o número da linha). Se você puder entrar em contato comigo off-line, adoraria ir ao fundo disso.
Brian Cryer
Sem blocos recolhidos, os números de linha estão ativados, ainda tem que subtrair 191, independentemente de onde é chamado. Eu sei ... estranho.
Daniel