У __LINE__ __FILE__ эквиваленты существуют в С#?
Для целей ведения журнала
__LINE__
__FILE__
были моими друзьями в C/С++. В Java, чтобы получить эту информацию, мне пришлось выбросить исключение и поймать его. Почему эти старые standbys так игнорируются на современных языках программирования? В их простоте есть что-то волшебное.
Ответы
Ответ 1
Это уродливее, но вы можете сделать что-то подобное на С#, используя 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());
Конечно, это связано с некоторыми накладными расходами.
Ответ 2
Информация о вызывающем абоненте добавлена в .NET 4.5. Это будет скомпилировано, большое улучшение перед необходимостью проверки stacktrace вручную.
public void Log(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Do logging
}
Просто назовите его таким образом, компилятор заполнит имя файла и номер строки для вас:
logger.Log("Hello!");
Ответ 3
Ближе всего к этому относится тот факт, что вы можете создать объект 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
сам. Пометив его как "Условный" ( "Отладка" ), мы гарантируем, что код будет удален из сборников релизов, что является одним из способов избежать затрат времени исполнения, когда это может не понадобиться.
Ответ 4
Поскольку трассировка стека содержит большую часть того, что вам нужно. Это не даст вам имя файла, но оно даст вам имя класса/метода. Он также содержит номер строки. Это не пренебрегается автоматическим. Вам просто нужно создать исключение, как вы это делаете в Java
Ответ 5
Здесь можно получить номер строки: http://askville.amazon.com/SimilarQuestions.do?req=line-numbers-stored-stack-trace-C%2523-application-throws-exception
Если вы используете log4net, вы можете получить номер строки и имя файла в своих журналах, но:
- это может уменьшить ваше приложение. производительность
- у вас должны быть файлы .PDB вместе с вашими сборками.
Ответ 6
С Информация о вызывающем абоненте (представленная в .NET 4.5) вы можете создать эквивалент __LINE__
и __FILE__
в С#:
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/С++, чтобы лучше понять, что они возвращают, и что-то вроде CurrentLineNumber()
и CurrentFileName()
может быть лучшим именем.
Преимущество использования информации о вызывающем абоненте над любым решением, использующим StackTrace
, заключается в том, что информация о строке и файле доступна как для отладки, так и для выпуска.
Ответ 7
Уже есть предложения по достижению того, чего вы хотите. Либо используйте объект StackTrace, либо лучше log4net.
В Java, чтобы получить эту информацию, мне пришлось выбросить исключение и поймать его.
Это не совсем так. Вы можете получить это, не отбрасывая исключений. Посмотрите на log4j. Он даже регистрирует ваш метод и имя класса, не загрязняя ваш код жестко закодированными строками, содержащими текущее имя метода (по крайней мере, я видел это в некоторых случаях).
Почему эти старые standbys так игнорируются на современных языках программирования?
Java и С# не используют (в последнем: чрезмерное использование) препроцессоров. И я думаю, что это хорошо. Злоупотребление препроцессорами для создания нечитаемого кода очень просто. И если программисты могут злоупотреблять какой-то техникой... они будут злоупотреблять ею.
Только заметка о производительности, которая, скорее всего, будет следующей, которая появляется в вашем уме:
Если вы используете StackTrace или log4net, вы всегда будете читать или слышать, что он медленный, потому что он использует Reflection. Я использую log4net, и я никогда не сталкивался с регистрацией в качестве шейки бутылки производительности. Если бы это было так, я могу декларативно дезактивировать (части) ведения журнала - без изменения исходного кода. Эта чистая красота по сравнению с удалением всех строк журнала в коде C/С++! (Кроме того: если производительность является основной целью, я бы использовал C/С++... она никогда не умрет, несмотря на Java и С#.)