Wie erhalte ich die aktuelle Zeilennummer?

117

Hier ist ein Beispiel dafür, was ich tun möchte:

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

Im Code über CurrentLineNumbersollte die Zeilennummer im Quellcode dieses Codeteils sein.

Wie kann ich das machen?

MonsterMMORPG
quelle
Sie können dies nicht zuverlässig tun, da der JIT-Compiler Optimierungen vornehmen kann (z. B. Inlining-Code), was bedeutet, dass Ihre Zeilennummern falsch sind.
Adrianbanks
1
Da Sie die Optimierung deaktivieren können, wenn Sie möchten, können Sie dies zuverlässig tun.
JWG
Mögliches Duplikat von Drucken Sie den Quelldateinamen und die Leinennummer in C #
Michael Freidgeim

Antworten:

175

In .NET 4.5 / C # 5 können Sie den Compiler veranlassen, diese Arbeit für Sie zu erledigen, indem Sie eine Dienstprogrammmethode schreiben, die die neuen Aufruferattribute verwendet:

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

Dies zeigt zum Beispiel Folgendes an:

Boo in Zeile 39 (SomeMethodSomewhere)

Dort finden [CallerFilePath]Sie auch den Pfad der ursprünglichen Codedatei.

Marc Gravell
quelle
Vielen Dank für die Antwort. ist das möglich auch objektnamen zu lernen? Oh, ich habe mit etwas anderem verwechselt. Was ich mich frage, ist asp.net 4.5 Website. globaler Fehlerfänger. den Fehler verursachten Objektnamen abfangen?
MonsterMMORPG
@MonsterMMORPG nein; nur die 3, die ich oben erwähnt habe
Marc Gravell
1
@MarcGravell erfordert dies, dass die Laufzeitumgebung ebenfalls 4,5 sein sollte ODER ist es eine Compilerfunktion?
Kuldeep
5
C # ist so gut gestaltet. Es hört nie auf, mich zu überraschen. Danke Marc!
nmit026
74

Verwenden Sie die StackFrame.GetFileLineNumber- Methode, zum Beispiel:

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

Siehe Scott Hanselman Blog - Eintrag für weitere Informationen.

[Bearbeiten: Folgendes hinzugefügt]

Berücksichtigen Sie für Benutzer von .Net 4.5 oder höher die Attribute CallerFilePath , CallerMethodName und CallerLineNumber im Namespace System.Runtime.CompilerServices. Beispielsweise:

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

Die Argumente müssen stringfür CallerMemberNameund CallerFilePathund intfür sein CallerLineNumberund einen Standardwert haben. Wenn Sie diese Attribute in Methodenparametern angeben, wird der Compiler angewiesen, zur Kompilierungszeit den entsprechenden Wert in den aufrufenden Code einzufügen. Dies bedeutet, dass die Verschleierung erfolgt. Weitere Informationen finden Sie unter Anruferinformationen .

akton
quelle
@MonsterMMORPG Dies funktioniert unabhängig davon, ob ein Fehler vorliegt oder nicht. Die StackFrame-Klasse betrachtet nur die Methode, die den aktuell ausgeführten Strom aufruft. Das erste Argument für den StackFrame-Konstruktor ist die Aufruftiefe (1), und das zweite Argument gibt an, dass Dateiinformationen benötigt werden.
Akton
3
Wenn Sie das StackFrameBeispiel auf Mono kompilieren , stellen Sie sicher, dass Sie es--debug zur Kompilierungszeit und zur Laufzeit verwenden
bernard paulus
StackFrameist in .NET Core nicht verfügbar. Verwenden Sie die Antwort von Marc Gravell.
Jesse Chisholm
Bei Verwendung des Standardwerts wird = string.Emptyder Fehler "Standardparameterwert für 'CallingFilePath' muss eine Konstante zur Kompilierungszeit sein" ausgelöst !
Stomy
1
@stomy Ich habe das Beispiel geändert, um doppelte Anführungszeichen ( "") anstelle von zu verwenden string.Empty.
Akton
21

Ich bevorzuge einen Liner also:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
iambriansreed
quelle
8
Es benötigt eine PDF-Datei, die wir im Allgemeinen nicht generieren / auf den Produktionsserver kopieren.
Deepak Sharma
4

Für diejenigen, die eine .NET 4.0+ -Methodenlösung benötigen:

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

So rufen Sie an:

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

Ausgabe:

Void Test () (FILENAME.cs: 104)

Schau hier!

Ändern Sie das Console.WriteLine-Format nach Ihren Wünschen!

Jared Burrows
quelle
3
funktioniert nicht in allen Fällen. Es benötigt immer eine PDF-Datei, die wir im Allgemeinen nicht generieren / auf den Produktionsserver kopieren. Versuchen Sie es mit dem Attribut C # 5.0 Caller *.
Deepak Sharma
2
Wenn Sie stattdessen System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));Folgendes verwenden, können Sie auf die Zeile im Ausgabefenster klicken und zu dieser Zeile in der Quelle weitergeleitet werden.
Jesse Chisholm
3

Wenn es sich in einem Try-Catch-Block befindet, verwenden Sie diesen.

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
quelle
1

In .NET 4.5 können Sie die Zeilennummer erhalten, indem Sie die Funktion erstellen:

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

Jedes Mal, wenn Sie anrufen LineNumber(), haben Sie die aktuelle Leitung. Dies hat gegenüber jeder Lösung, die StackTrace verwendet, den Vorteil, dass sie sowohl beim Debuggen als auch beim Release funktionieren sollte.

Wenn man also die ursprüngliche Anfrage von dem nimmt, was benötigt wird, würde es werden:

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

Dies baut auf der hervorragenden Antwort von Marc Gravell auf.

Brian Cryer
quelle
Dies gibt nicht die richtige Zeilennummer zurück. Ich muss 191 subtrahieren, um es aus irgendeinem Grund richtig zu machen.
Daniel
Interessant. Funktioniert hier gut für mich. Haben Sie Linknummern in der IDE aktiviert? Wenn Sie diese Funktion an verschiedenen Stellen in der Datei aufrufen, müssen Sie dann noch 191 subtrahieren? Dies ist entweder ein Compiler-Fehler (unwahrscheinlich, aber möglich) oder ein reduzierter Block auf Ihrer Seite (obwohl dies nicht die Richtigkeit der Zeilennummern verhindern sollte, könnte dies den Unterschied erklären, wenn Sie gezählt haben, anstatt die Zeilennummer nachzuschlagen). Wenn Sie mich offline kontaktieren können, würde ich gerne auf den Grund gehen.
Brian Cryer
Keine reduzierten Blöcke, Zeilennummern sind aktiviert, müssen immer noch 191 subtrahieren, unabhängig davon, woher sie aufgerufen werden. Ich weiß ... komisch.
Daniel