Come ottengo il numero di riga corrente?


117

Ecco un esempio di quello che voglio fare:

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

Nel codice sopra CurrentLineNumber, dovrebbe essere il numero di riga nel codice sorgente di questo pezzo di codice.

Come lo posso fare?


Non è possibile farlo in modo affidabile , poiché il compilatore JIT può eseguire ottimizzazioni (ad esempio codice inlining), il che significa che i numeri di riga saranno errati.
adrianbanks

1
Dal momento che è possibile disattivare l'ottimizzazione se si desidera, è possibile in modo affidabile fare questo.
jwg

Risposte:


175

In .NET 4.5 / C # 5, puoi fare in modo che il compilatore esegua questo lavoro per te, scrivendo un metodo di utilità che utilizza i nuovi attributi del chiamante:

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 + ")");
}

Questo mostrerà, ad esempio:

Boo alla riga 39 (SomeMethodSomewhere)

C'è anche [CallerFilePath]che ti dice il percorso del file di codice originale.


Grazie mille per la risposta. è possibile imparare anche il nome dell'oggetto? oh mi sono confuso con qualcos'altro. quello che mi chiedo è il sito web asp.net 4.5. rilevatore di errori globale. rilevare l'errore causato nome oggetto?
MonsterMMORPG

@MonsterMMORPG no; solo i 3 che ho citato sopra
Marc Gravell

1
@ MarcGravell richiede che anche l'ambiente di runtime sia 4.5 O è una funzionalità del compilatore?
kuldeep

5
C # è così ben progettato. Non finisce mai di stupirmi. Grazie Marc!
nmit026

74

Utilizza il metodo StackFrame.GetFileLineNumber , ad esempio:

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

Per ulteriori informazioni, vedere la voce del blog di Scott Hanselman .

[Modifica: aggiunto quanto segue]

Per coloro che utilizzano .Net 4.5 o versioni successive, considera gli attributi CallerFilePath , CallerMethodName e CallerLineNumber nello spazio dei nomi System.Runtime.CompilerServices. Per esempio:

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

Gli argomenti devono essere stringfor CallerMemberNameand CallerFilePathand an intfor CallerLineNumbere devono avere un valore predefinito. La specifica di questi attributi sui parametri del metodo indica al compilatore di inserire il valore appropriato nel codice chiamante in fase di compilazione, il che significa che funziona tramite offuscamento. Vedere Informazioni sul chiamante per ulteriori informazioni.


@MonsterMMORPG Funziona indipendentemente dal fatto che ci sia o meno un errore. La classe StackFrame sta solo guardando il metodo che chiama la corrente in esecuzione. Il primo argomento del costruttore StackFrame è la profondità della chiamata (1) e il secondo argomento indica che sono necessarie le informazioni sul file.
Akton

3
Se stai compilando l' StackFrameesempio su Mono , assicurati di usarlo--debug in fase di compilazione e in fase di esecuzione
bernard paulus

StackFramenon è disponibile in .NET Core. Usa la risposta di Marc Gravell.
Jesse Chisholm

L'utilizzo del valore predefinito = string.Emptygenera l'errore "Il valore del parametro predefinito per 'callingFilePath' deve essere una costante in fase di compilazione" !
stomy

1
@stomy Ho cambiato il file examp [per usare le virgolette doppie ( "") invece di string.Empty.
akton

21

Preferisco una riga quindi:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();

8
necessita di un file .pdb .. che generalmente non generiamo / copiamo sul server di produzione.
Deepak Sharma

4

Per coloro che necessitano di una soluzione di metodo .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);
}

Come chiamare:

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

Produzione:

Void Test () (FILENAME.cs: 104)

Guarda qui!

Cambia il formato Console.WriteLine come preferisci!


3
non funzionerà in tutti i casi .. necessita sempre del file .pdb, che generalmente non generiamo / copiamo sul server di produzione. provare con C # 5.0 Caller * attributo.
Deepak Sharma

2
Se invece usi questo: System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));puoi fare clic sulla riga nella finestra di output ed essere portato a quella riga nel sorgente.
Jesse Chisholm

3

Se è in un blocco try catch, usa questo.

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

1

In .NET 4.5 è possibile ottenere il numero di riga creando la funzione:

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

Quindi ogni volta che chiami LineNumber()avrai la linea corrente. Questo ha il vantaggio rispetto a qualsiasi soluzione che utilizza StackTrace che dovrebbe funzionare sia nel debug che nel rilascio.

Quindi, prendendo la richiesta originale di ciò che è richiesto, diventerebbe:

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

Ciò si basa sull'eccellente risposta di Marc Gravell.


Ciò non restituisce il numero di riga corretto. Devo sottrarre 191 per farlo bene per qualche motivo.
Daniel

Interessante. Funziona bene qui per me. Hai i numeri di collegamento attivati ​​nell'IDE? Se chiami questa funzione da diversi punti del file devi comunque sottrarre 191? Questo sarà un bug del compilatore (improbabile, ma possibile) o un blocco compresso sulla tua pagina (sebbene ciò non dovrebbe impedire che i numeri di riga siano corretti, potrebbe spiegare la differenza se stavi contando piuttosto che cercando il numero di riga). Se puoi contattarmi offline, mi piacerebbe arrivare in fondo.
Brian Cryer

Nessun blocco compresso, i numeri di riga sono attivati, è comunque necessario sottrarre 191 indipendentemente da dove viene chiamato. Lo so ... strano.
Daniel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.