Bagaimana cara mendapatkan nomor baris saat ini?

118

Berikut adalah contoh yang ingin saya lakukan:

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

Dalam kode di atas CurrentLineNumber, harus menjadi nomor baris dalam kode sumber dari bagian kode ini.

Bagaimana saya bisa melakukan itu?

MonsterMMORPG
sumber
Anda tidak dapat melakukan ini dengan andal , karena kompilator JIT dapat melakukan pengoptimalan (mis. Kode sebaris), yang berarti nomor baris Anda akan salah.
adrianbanks
1
Karena Anda dapat menonaktifkan pengoptimalan jika mau, Anda dapat melakukannya dengan andal.
jwg
Kemungkinan duplikat dari Cetak nama file dan nomor linen sumber di C #
Michael Freidgeim

Jawaban:

176

Di .NET 4.5 / C # 5, Anda bisa meminta kompiler untuk melakukan pekerjaan ini untuk Anda, dengan menulis metode utilitas yang menggunakan atribut pemanggil baru:

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

Ini akan menampilkan, misalnya:

Boo di baris 39 (SomeMethodSomewhere)

Ada juga [CallerFilePath]yang memberi tahu Anda jalur file kode asli.

Marc Gravell
sumber
terima kasih banyak atas jawabannya. apakah itu mungkin untuk mempelajari juga nama objek? oh saya bingung dengan yang lain. yang saya heran adalah situs web asp.net 4.5. penangkap kesalahan global. menangkap kesalahan yang disebabkan nama objek?
MonsterMMORPG
@Monster_monster tidak; hanya 3 yang saya sebutkan di atas
Marc Gravell
1
@ MarcGravell apakah ini mensyaratkan bahwa lingkungan waktu proses juga harus 4,5 ATAU apakah itu fitur kompilator?
kuldeep
5
C # dirancang dengan sangat baik. Itu tidak pernah berhenti membuat saya takjub. Terima kasih Marc!
nmit026
75

Gunakan metode StackFrame.GetFileLineNumber , misalnya:

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

Lihat entri Blog Scott Hanselman untuk informasi lebih lanjut.

[Edit: Menambahkan berikut ini]

Bagi mereka yang menggunakan .Net 4.5 atau lebih baru, pertimbangkan atribut CallerFilePath , CallerMethodName dan CallerLineNumber di namespace System.Runtime.CompilerServices. Sebagai contoh:

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

Argumen harus stringuntuk CallerMemberNamedan CallerFilePathdan intuntuk CallerLineNumberdan harus memiliki nilai default. Menentukan atribut ini pada parameter metode menginstruksikan compiler untuk memasukkan nilai yang sesuai dalam kode panggilan pada waktu kompilasi, yang berarti ia bekerja melalui obfuscation. Lihat Informasi Penelepon untuk informasi lebih lanjut.

akton
sumber
@MonsterMMORPG Ini berfungsi terlepas dari apakah ada kesalahan atau tidak. Kelas StackFrame hanya melihat metode yang memanggil arus yang sedang dieksekusi. Argumen pertama untuk konstruktor StackFrame adalah kedalaman panggilan (1) dan argumen kedua menunjukkan bahwa informasi file diperlukan.
akton
3
Jika Anda mengompilasi StackFramecontoh di Mono , pastikan untuk menggunakan--debug pada waktu kompilasi dan waktu proses
bernard paulus
StackFrametidak tersedia di .NET Core. Gunakan jawaban Marc Gravell.
Jesse Chisholm
Menggunakan nilai default = string.Emptyakan memunculkan error "Nilai parameter default untuk 'callingFilePath' harus berupa konstanta waktu kompilasi" !
Stomy
1
@stomy Saya mengubah examp [le untuk menggunakan tanda kutip ganda ( "") sebagai ganti string.Empty.
akton
22

Saya lebih suka satu liner jadi:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
iambriansreed
sumber
8
itu membutuhkan file .pdb .. yang biasanya tidak kami buat / salin ke server produksi.
Deepak Sharma
4

Bagi mereka yang membutuhkan solusi metode .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);
}

Bagaimana cara menelepon:

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

Keluaran:

Void Test () (FILENAME.cs: 104)

Lihat di sini!

Ubah format Console.WriteLine sesuka Anda!

Jared Burrows
sumber
3
tidak akan berfungsi di semua kasus .. ia membutuhkan file .pdb selalu, yang biasanya tidak kami buat / salin ke server produksi. coba dengan atribut C # 5.0 Caller *.
Deepak Sharma
2
Jika Anda menggunakan ini: System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));maka Anda dapat mengklik baris di jendela keluaran dan dibawa ke baris tersebut di sumber.
Jesse Chisholm
3

Jika dalam mencoba menangkap blok gunakan ini.

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

Di .NET 4.5 Anda bisa mendapatkan nomor baris dengan membuat fungsi:

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

Kemudian setiap kali Anda menelepon, LineNumber()Anda akan mendapatkan saluran saat ini. Ini memiliki keunggulan dibandingkan solusi apa pun yang menggunakan StackTrace yang seharusnya berfungsi baik di debug maupun rilis.

Jadi mengambil permintaan asli dari apa yang dibutuhkan, itu akan menjadi:

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

Ini membangun jawaban luar biasa dari Marc Gravell.

Brian Cryer
sumber
Ini tidak mengembalikan nomor baris yang benar. Saya harus mengurangi 191 untuk membuatnya benar karena suatu alasan.
Daniel
Menarik. Bekerja dengan baik di sini untuk saya. Apakah Anda mengaktifkan nomor tautan di IDE? Jika Anda memanggil fungsi ini dari tempat berbeda dalam file, apakah Anda masih harus mengurangi 191? Ini bisa berupa bug compiler (tidak mungkin, tapi mungkin) atau blok yang diciutkan pada halaman Anda (sementara itu seharusnya tidak mencegah nomor baris menjadi benar, ini mungkin menjelaskan perbedaannya jika Anda menghitung daripada mencari nomor baris). Jika Anda dapat menghubungi saya secara offline, saya ingin membacanya.
Brian Cryer
Tidak ada blok yang runtuh, nomor baris dihidupkan, masih harus mengurangi 191 terlepas dari mana asalnya. Aku tahu ... aneh.
Daniel