Существуют ли эквиваленты __LINE__ __FILE__ в C #?

Asked
Viewd22429

48

Для ведения журнала

 __LINE__ 
__FILE__ 
 

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

8 ответов

30

Это уродливо, но вы можете сделать что-то подобное на 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());
 

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

  • макросы снова являются функцией препроцессора. Имя макроса заменяется в коде телом макроса перед его компиляцией. В C # нет макросов.

    Ed S.31 марта 2009, 02:06
  • Мне нужно узнать об условных компиляциях в приложении C #, но доступно даже больше информации, чем я предполагал. Мне также нужно узнать о макросах и их поддержке на C #. Спасибо за ответ.

    ojblass30 марта 2009, 23:26
  • … и поэтому вам действительно следует заключить такой код в блок #if DEBUG #endif

    Peter Lillevold30 марта 2009, 07:12
1

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

  • Вам не нужно создавать исключение - см. ответ Эда Свангрена. Проблема в том, что это значительно медленнее, чем встраивание информации во время сборки.

    Jon Skeet30 марта 2009, 07:07
0

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

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

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

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

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

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

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

1

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

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

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

Наиболее близким к ним является тот факт, что вы можете создать объект 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. Помечая его как «Условный» («Отладка»), мы гарантируем, что код будет удален из сборок выпуска, что является одним из способов избежать затрат времени выполнения там, где он может не понадобиться.