Подтвердить что ты не робот

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

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

__LINE__ 
__FILE__ 

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

4b9b3361

Ответ 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 и С#.)