Як отримати номер поточного рядка?


117

Ось приклад того, що я хочу зробити:

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

У коді вище CurrentLineNumber, повинен бути номер рядка у вихідному коді цього фрагмента коду.

Як я можу це зробити?


Ви не можете надійно зробити це, оскільки компілятор JIT може зробити оптимізацію (наприклад, вбудований код), що означає, що номери рядків будуть неправильними.
adrianbanks

1
Оскільки ви можете вимкнути оптимізацію, якщо хочете, ви можете надійно це зробити.
jwg

Відповіді:


175

У .NET 4.5 / C # 5 ви можете змусити компілятора зробити цю роботу за вас, написавши утилітний метод, який використовує нові атрибути виклику:

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

Це відобразиться, наприклад:

Бу в рядку 39 (SomeMethodSomewhere)

Там же [CallerFilePath]ви знаєте шлях до вихідного файлу коду.


велике спасибі за відповідь. чи можливо дізнатися також ім'я об'єкта? ой я переплутав щось інше. що мені цікаво - це сайт asp.net 4.5. глобальний виловлювач помилок. зловити причину помилки, назва об’єкта?
MonsterMMORPG

@MonsterMMORPG nope; лише 3, про які я згадував вище
Марк Гравелл

1
@MarcGravell це вимагає, щоб середовище часу виконання також було 4,5 АБО це функція компілятора?
kuldeep

5
C # настільки добре розроблений. Це ніколи не перестає мене дивувати. Дякую Марку!
nmit026

74

Використовуйте метод StackFrame.GetFileLineNumber , наприклад:

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

Дивіться запис у блозі Скотта Хензельмана отримання додаткової інформації .

[Редагувати: Додано наступне]

Для тих, хто використовує .Net 4.5 або новішої версії, розгляньте атрибути CallerFilePath , CallerMethodName та CallerLineNumber у просторі імен System.Runtime.CompilerServices. Наприклад:

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

Аргументи повинні бути stringдля CallerMemberNameі CallerFilePathі intдля CallerLineNumberі повинні мати значення за замовчуванням. Визначаючи ці атрибути в параметрах методу, вказує компілятору вставити відповідне значення в код виклику під час компіляції, тобто це працює через обфускування. Див. Інформацію про абонента для отримання додаткової інформації.


@MonsterMMORPG Це працює незалежно від того, є помилка чи ні. Клас StackFrame просто дивиться на метод виклику поточного виконується. Перший аргумент конструктора StackFrame - це глибина виклику (1), а другий аргумент вказує на необхідність інформації про файл.
akton

3
Якщо ви збираєте StackFrameприклад на Mono , не забудьте скористатися--debug під час компіляції та під час виконання
Bernard paulus

StackFrameнедоступний у .NET Core. Використовуйте відповідь Марка Гравелла.
Джессі Чісгольм

Використання значення за замовчуванням = string.Emptyкидає помилку "Значення параметра за замовчуванням для 'callFilePath' повинно бути констатою часу компіляції" !
стом

1
@stomy Я змінив іспит [le, щоб використовувати подвійні лапки ( "") замість string.Empty.
актон

21

Я віддаю перевагу одному вкладишам так:

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

8
йому потрібен файл .pdb .. який ми зазвичай не генеруємо / копіюємо на виробничий сервер.
Діпак Шарма

4

Для тих, хто потребує методу рішення .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);
}

Як зателефонувати:

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

Вихід:

Недійсний тест () (FILENAME.cs: 104)

Послухайте!

Змініть формат Console.WriteLine, як вам подобається!


3
працюватиме не у всіх випадках .. йому завжди потрібен .pdb файл, який ми, як правило, не генеруємо / копіюємо на виробничий сервер. спробуйте атрибут C # 5.0 Caller *.
Діпак Шарма

2
Якщо ви замість цього використовуєте це: System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));тоді ви можете натиснути рядок у вікні виводу та перейти до цього рядка у джерелі.
Джессі Чизгольм

3

Якщо його в блоці спробу лову, скористайтеся цим.

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

1

У .NET 4.5 ви можете отримати номер рядка, створивши функцію:

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

Потім кожен раз, коли ви телефонуєте LineNumber() ви матимете поточну лінію. Це має перевагу перед будь-яким рішенням, що використовує StackTrace, що воно має працювати як у налагодженні, так і у випуску.

Отже, беручи за собою початковий запит того, що потрібно, це стане:

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

Це спирається на чудову відповідь Марка Гравелла.


Це не повертає правильний номер рядка. Мені потрібно відняти 191, щоб з якихось причин виправити це.
Даніель

Цікаво. Тут чудово працює для мене. У вас включені номери посилань у IDE? Якщо ви викликаєте цю функцію з різних місць у файлі, вам все-таки потрібно відняти 191? Це буде або помилка компілятора (малоймовірна, але можлива), або згорнутий блок на вашій сторінці (хоча це не повинно перешкоджати правильності номерів рядків, це може пояснити різницю, якщо ви рахували, а не шукали номер рядка). Якщо ви можете зв’язатися зі мною офлайн, я хотів би досягти цього.
Брайан Крейдер

Немає згорнутих блоків, номери рядків увімкнено, все ж треба відняти 191 незалежно від того, звідки його викликано. Я знаю ... дивно.
Даніель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.