Существуют ли __LINE__ __FILE__ эквиваленты в C #? - PullRequest
40 голосов
/ 30 марта 2009

Для целей регистрации

__LINE__ 
__FILE__ 

были моими друзьями в C / C ++. В Java, чтобы получить эту информацию, мне пришлось выбросить исключение и поймать его. Почему эти старые резервы так игнорируются в современных языках программирования? В их простоте есть что-то волшебное.

Ответы [ 7 ]

73 голосов
/ 12 июля 2012

Информация о вызывающем абоненте была добавлена ​​в .NET 4.5. Это будет скомпилировано, что значительно улучшит ручную проверку трассировки стека.

public void Log(string message,
        [CallerFilePath] string filePath = "",
        [CallerLineNumber] int lineNumber = 0)
{
    // Do logging
}

Просто назовите его таким образом, компилятор заполнит имя файла и номер строки для вас:

logger.Log("Hello!");
26 голосов
/ 30 марта 2009

Это ужаснее, но вы можете сделать что-то подобное в C #, используя StackTrace и StackFrame классы:

StackTrace st = new StackTrace(new StackFrame(true));
Console.WriteLine(" Stack trace for current level: {0}", st.ToString());
StackFrame sf = st.GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Method: {0}", sf.GetMethod().Name);
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());

Конечно, это связано с некоторыми накладными расходами.

11 голосов
/ 30 марта 2009

Наиболее близким к ним является тот факт, что вы можете создать объект StackTrace и узнать имя метода в верхней части стека, чтобы вы могли приблизиться к функциональности макроса __FUNCTION__.

StackTrace stackTrace = new StackTrace();           
StackFrame[] stackFrames = stackTrace.GetFrames();  

foreach (StackFrame stackFrame in stackFrames)
    Console.WriteLine(stackFrame.GetMethod().Name);   

Чтобы сократить затраты на ручную печать, а также код времени выполнения, вы можете написать вспомогательный метод:

[Conditional("Debug")]
public void LogMethodName()
{
    Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name);
}

Обратите внимание, как мы получаем кадр 1, так как кадр 0 будет LogMethodName сам по себе. Помечая его как Условный («Отладка»), мы гарантируем, что код будет удален из сборок выпуска, что является одним из способов избежать затрат времени выполнения, когда это может не понадобиться.

6 голосов
/ 23 мая 2017

С помощью Информация о вызывающем абоненте (введено в .NET 4.5) вы можете создать эквивалент __LINE__ и __FILE__ в C #:

static int __LINE__([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
    return lineNumber;
}
static string __FILE__([System.Runtime.CompilerServices.CallerFilePath] string fileName = "")
{
    return fileName;
}

Единственное, что нужно помнить, это то, что это функции, а не директивы компилятора.

Так, например:

MessageBox.Show("Line " + __LINE__() + " in " + __FILE__());

Если бы вы использовали это на практике, я бы предложил другие имена. Я использовал имена C / C ++ только для того, чтобы было понятнее, что они возвращают, и что-то вроде CurrentLineNumber() и CurrentFileName() может быть лучше имен.

Преимущество использования информации о вызывающем абоненте перед любым решением, использующим StackTrace, заключается в том, что информация о строках и файлах доступна как для отладки, так и для выпуска.

1 голос
/ 30 марта 2009

Вот способ получить номер строки: http://askville.amazon.com/SimilarQuestions.do?req=line-numbers-stored-stack-trace-C%2523-application-throws-exception

Если вы используете log4net, вы можете получить номер строки и имя файла в ваших журналах, но:

  • это может уменьшить ваше приложение. производительность
  • у вас должны быть файлы .PDB вместе с вашими сборками.
1 голос
/ 30 марта 2009

Потому что трассировка стека содержит большую часть того, что вам нужно. Он не даст вам имя файла, но даст имя класса / метода. Он также содержит номер строки. Это не пренебрегают, это автоматически. Вам просто нужно выдать исключение, как вы делаете это в Java

0 голосов
/ 30 марта 2009

Уже есть несколько предложений для достижения того, чего вы хотите. Либо используйте объект StackTrace, либо лучше log4net.

В Java, чтобы получить эту информацию, мне пришлось выбросить исключение и поймать его.

Это не совсем так. Вы можете иметь это без исключений тоже. Посмотрите на log4j. Он даже регистрирует ваш метод и имя класса, не загрязняя ваш код жестко закодированными строками, содержащими текущее имя метода (по крайней мере, я видел это в некоторых случаях).

Почему эти старые резервы так игнорируются в современных языках программирования?

Java и C # не используют (в последнем случае: чрезмерное использование) препроцессоры. И я думаю, что это хорошо. Злоупотреблять препроцессорами для создания нечитаемого кода очень легко. И если программисты могут злоупотреблять какой-либо техникой ... они будут злоупотреблять ею.

Просто заметка о производительности, которая, скорее всего, будет следующей, которая всплывает у вас в голове:

Если вы используете StackTrace или log4net, вы всегда будете читать или слышать, что он медленный, потому что он использует Reflection. Я использую log4net, и я никогда не сталкивался с ведением журнала в качестве горлышка производительности бутылки. Если это так, я могу декларативно деактивировать (части) журналирование - без изменения исходного кода. Это чистая красота по сравнению с удалением всех строк журнала в коде C / C ++! (Кроме того: если производительность является основной целью, я бы использовал C / C ++ ... она никогда не умрет, несмотря на Java и C #.)

...