Как мне узнать текущий номер строки?

118

Вот пример того, что я хочу сделать:

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

В коде выше CurrentLineNumberдолжен быть номер строки в исходном коде этого фрагмента кода.

Как я могу это сделать?

MonsterMMORPG
источник
Вы не можете сделать это надежно , поскольку JIT-компилятор может выполнять оптимизацию (например, встраивание кода), что означает, что ваши номера строк будут неправильными.
Адрианбэнкс
1
Так как вы можете отключить оптимизацию, если хотите, вы можете сделать это надежно.
jwg 05
Возможный дубликат печати исходного имени файла и номера строки в C #
Майкл Фрейдгейм

Ответы:

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 нет; только трое, о которых я упоминал выше
Марк Грейвелл
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), а второй аргумент указывает, что необходима информация о файле.
Актон
3
Если вы компилируете StackFrameпример на Mono , обязательно используйте--debug во время компиляции и во время выполнения
Бернард Паулус
StackFrameнедоступен в .NET Core. Воспользуйтесь ответом Марка Гравелла.
Джесси
Использование значения по умолчанию = string.Emptyвызывает ошибку «Значение параметра по умолчанию для 'CallingFilePath' должно быть константой времени компиляции» !
stomy
1
@stomy Я изменил examp [le, чтобы использовать двойные кавычки ( "") вместо string.Empty.
Актон 06
22

Я предпочитаю одинарные вкладыши:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();
iambriansreed
источник
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 catch, используйте это.

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
источник
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, чтобы понять это правильно.
Daniel
Интересный. У меня здесь отлично работает. Включены ли номера ссылок в IDE? Если вы вызываете эту функцию из разных мест в файле, вам все равно нужно вычесть 191? Это будет либо ошибка компилятора (маловероятная, но возможная), либо свернутый блок на вашей странице (хотя это не должно препятствовать правильности номеров строк, это могло бы объяснить разницу, если бы вы считали, а не искали номер строки). Если вы можете связаться со мной в автономном режиме, я бы хотел разобраться в этом.
Брайан Крайер
Никаких свернутых блоков, номера строк включены, все равно нужно вычесть 191 независимо от того, откуда он вызван. Я знаю ... странно.
Daniel