Есть ли время доступа к номерам строк в С#?
Я пишу программу на С#, используя Visual Studio 2010, где я хочу записать определенные события в файл журнала и включить номер строки, в которой код был включен, когда это произошло.
Я нашел только два способа записи номеров строк - CallerLineNumber, для которого требуется .Net 4.5/С# 5 (я нацелен на .Net 4) и StackFrame.GetFileLineNumber, который, по-видимому, требует отладочной сборки и файла pdb для работаю правильно, и я создаю сборку релиза и файл pdb.
Но здесь то, что я не получаю - оба из вышеперечисленных решений выполняются, но номера строк - это время компиляции. Почему требуется время выполнения?
Я мог бы ввести правильный номер строки в качестве литеральной константы, просто посмотрев на нижнюю часть экрана, где он говорит что-то вроде "ln 175".,
LogEvent("It happened at line 175");
но проблема в том, что если я отредактирую код до строки 175, мой литерал может быть более правильным. Но компилятор знает правильный номер строки, и в прошлом я использовал языки программирования, которые могли бы просто ввести правильный номер строки в качестве постоянной времени компиляции. (например, ANSI C и Microsoft С++ поддерживают предопределенный макрос, называемый
_LINE_
) Есть ли способ получить С# для этого? Если нет решений для моей проблемы?
Ответы
Ответ 1
Нет, у С# нет препроцессора макроса или каких-либо функций метапрограммирования, поэтому на всем языке не существует решений "Время компиляции". Но есть сторонние макроязыки, которые вы можете использовать, если вам нужно, но, конечно, это усложняет процесс сборки, Visual Studio не просто выяснит, как построить его самостоятельно.
Вы даже можете использовать препроцессор C, если хотите. (предполагая компилятор MSVC)
cl.exe /TC /P /C /EP something.cs > something.raw.cs
-
cl.exe
- компилятор C
-
/TC
сообщает компилятору C обрабатывать все файлы как источники C, несмотря на их расширения.
-
/P
сообщает компилятору C только предварительно обрабатывать файл, не компилируя его
-
/C
сохраняет комментарии
-
/EP
не позволяет компилятору генерировать директивы #line, что компилятор С# не понимает
Это позволит вам использовать #include
, #define
и #if
, а также __FILE__
и __LINE__
в вашей программе на С#, но снова вам нужно настроить Visual Studio для выполнения этого дополнительного этапа компиляции, или использовать другую систему сборки.
Ответ 2
CAVEATS. Это НЕ ответ на OP. Я знаю это. Но люди, которые ищут что-то подобное, могут найти эту страницу.
- Это не о .NET 4.
- Это, в конечном счете, решение для времени выполнения.
Но VS 2015, С#,.NET Core или .NET 4.5 позволяют:
using System.Runtime.CompilerServices;
using System.Diagnostics;
public static String CurrentLocation(
[CallerFilePath] string file = null,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string method = null)
{
String location = file;
if (lineNumber != 0)
{
location += "(" + lineNumber.ToString() + ")";
}
if (!String.IsNullOrWhiteSpace(method))
{
location += ": " + method;
}
if (!String.IsNullOrWhiteSpace(location))
{
location += ": ";
}
return location;
}
[ОБНОВЛЕННОЕ ИСПОЛЬЗОВАНИЕ]
С использованием чего-то вроде:
Console.Error.WriteLine(CurrentLocation() + "some message");
или
Debug.WriteLine(CurrentLocation() + "some message");
Ответ 3
Один из вариантов заключается в использовании класса StackTrace, например
[Conditional("DEBUG")]
public static void DebugPrintTrace()
{
StackTrace st = new StackTrace(true);
StackFrame sf = st.GetFrame(1);
Console.WriteLine("Trace "
+ sf.GetFileName() + " "
+ sf.GetMethod().Name + ":"
+ sf.GetFileLineNumber() + "\n");
}
Ответ 4
По-моему, номера строк - неправильный подход. Позвольте мне объяснить:
Насколько уникален номер строки 175? Даже если вы найдете решение, следующий вопрос: какой файл был? И он повторится: если вы знаете файл, вы спросите себя: какая версия файла была такой? И вы будете интегрировать номер версии вашей системы управления версиями. Как только вы это сделаете, встанет вопрос: кто звонил в этот код.
Если вы отлаживаете исключение, используйте отладчик и прервите первые исключения.
Если вы анализируете проблему производительности, номера строк не имеют значения, что-то уникальное. Попробуйте профайлер памяти.
Если ваши методы слишком длинны, чтобы идентифицировать проблемы, реорганизуйте свой код и сделайте методы короче. С помощью коротких методов вы можете использовать структуру AOP, такую как PostSharp, с ее аспектом ведения журнала, чтобы достичь хотя бы функции CallerMemberName
. Он доступен для .NET 2.0, и очень легко добавить журнал и удалить журнал, а не удалять отдельные строки в коде.