Здравствуйте, Аноним, Вы писали:
А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?
Для трассировки стека используется класс System.Diagnostics.StackTrace:
System.Diagnostics.StackTrace s =
new System.Diagnostics.StackTrace(0);
Console.WriteLine(s.GetFrame(0).GetMethod().Name);
Метод GetFrame(0) возвращает первый фрейм объекта StackTrace, т. е. как раз тот, который в данный момент выполняется. Метод GetMethod() возвращает ссылку на объект MethodBase, соответствующий методу заданного фрейма.
Соответственно, для получения всего стека вызовов можно использовать код:
System.Diagnostics.StackTrace s =
new System.Diagnostics.StackTrace(0);
for (int i=0; i< s.FrameCount; i++)
{
Console.WriteLine(s.GetFrame(i).GetMethod().Name);
}
Здравствуйте, Аноним, Вы писали:
А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?
MethodBase.GetCurrentMethod();
Re[2]: Как узнать имя функции?
От:
Аноним
Дата:
01.03.09 15:05
Оценка:
А можно ли писать что-то вроде
#define _FUNCNAME_ new StackTrace(0).GetFrame(0).GetMethod().Name
?,
а то как-то длинно получается, если каждый часто нужно.
Re[2]: Как узнать имя функции?
От:
Аноним
Дата:
01.03.09 15:23
Оценка:
Здравствуйте, Pavel_Agurov, Вы писали:
Этот способ укажет текущий исполняемый метод, который может отличаться, в случае инлайнинга, от метода содержащего этот код.
Re: Как узнать имя функции?
От:
Аноним
Дата:
01.03.09 16:01
Оценка:
Пока сделал так (только начал изучать C#, поэтому возможно криво):
Здравствуйте, Аноним, Вы писали:
А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?
Почему бы не попробовать log4net? Потратите немного времени на его изучение сейчас, зато сэкономите много потом.
Там есть паттерн, который вам нужен (%M) — логирует имя метода, из которого произошел вызов.
Здравствуйте, Аноним, Вы писали:
А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?
Если требуется логирование многих разных по сути и природе методов, то хардкодить это в тело самих методов — очень плохая идея. Это как раз тот случай, когда можно с пользой применить аспекты (AOP).
Пример простого перехватчика можно посмотреть здесь
Здравствуйте, maxnk, Вы писали:
А>>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ? M>Почему бы не попробовать log4net? Потратите немного времени на его изучение сейчас, зато сэкономите много потом. M>Там есть паттерн, который вам нужен (%M) — логирует имя метода, из которого произошел вызов.
А каким образом он узнаёт имя метода знаешь?
Help will always be given at Hogwarts to those who ask for it.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Как узнать имя функции?
От:
Аноним
Дата:
02.03.09 08:05
Оценка:
Здравствуйте, Lloyd, Вы писали:
L>Получение StackTrace-а — очень тяжелая операция. Используй MethodBase
Для полноты картины хотелось бы отметить, что MethodBase.GetCurrentMethod также использует StackTrace, но поскольку это выполняется в native коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.
Тут, я думаю, можно пожертвовать немного производительности во имя удобств, предоставляемых log4net.
Обычно логгинг в production включен только на сообщения уровня ERROR (причем, чаще всего это обработка исключений) и все, что имеет более низкий уровень, просто пропускается. Соответственно, StackTrace достаточно редко будет использоваться.
Ну конечно, если нужно логировать что-то постоянно и много, то другие варианты нужно использовать.
Здравствуйте, Аноним, Вы писали:
А>Для полноты картины хотелось бы отметить, что MethodBase.GetCurrentMethod также использует StackTrace, но поскольку это выполняется в native коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.
С чего вы взяли, что GetCurrentMethod использует StackTrace? Вот реализация, которую мне показывает Reflector:
L>Как видите, никакого упоминания StackTrace-а и в помине нет.
Это ж вершина, предлагаю заглянуть чуть дальше (я же упомянул о native коде) в SSCLI:
internal static MethodBase InternalGetCurrentMethod(ref StackCrawlMark stackMark)
{
RuntimeMethodHandle method = RuntimeMethodHandle.GetCurrentMethod(ref stackMark);
if (method.IsNullHandle())
return null;
// If C<Foo>.m<Bar> was called, GetCurrentMethod returns C<object>.m<object>. We cannot
// get know that the instantiation used Foo or Bar at that point. So the next best thing
// is to return C<T>.m<P> and that's what GetTypicalMethodDefinition will do for us. method = method.GetTypicalMethodDefinition();
return RuntimeType.GetMethodBase(method);
}
...
// Return the MethodInfo that represents the current method (two above this one)
FCIMPL1(MethodDesc*, RuntimeMethodHandle::GetCurrentMethod, StackCrawlMark* stackMark) {
CONTRACTL {
THROWS;
DISABLED(GC_TRIGGERS);
MODE_COOPERATIVE;
SO_TOLERANT;
}
CONTRACTL_END;
SkipStruct skip;
skip.pStackMark = stackMark;
skip.pMeth = 0;
HELPER_METHOD_FRAME_BEGIN_RET_0();
StackWalkFunctions(GetThread(), SkipMethods, &skip);
HELPER_METHOD_FRAME_END();
return skip.pMeth;
}
....
StackWalkAction StackWalkFunctions(Thread * thread,
PSTACKWALKFRAMESCALLBACK pCallback,
VOID * pData)
{
// Note: there are cases (i.e., exception handling) where we may never return from this function. This means
// that any C++ destructors pushed in this function will never execute, and it means that this function can
// never have a dynamic contract.
STATIC_CONTRACT_WRAPPER;
return thread->StackWalkFrames(pCallback, pData, FUNCTIONSONLY);
}
....
ну и далее соотв. цикл по стэку, не привожу, желающие могут посмотреть сами.
Кстати, в методе StackWalkFrames есть интересный комментарий, что на x64 путешествие по стэку синхронизируется с пом. критической секции, так что как ни крути, получение имени метода таким способом не самая дешевая операция, а на x64 может неожиданно повлиять на производительность, в случае интенсивного использования в многопоточном приложении.
Здравствуйте, Lloyd, Вы писали:
А>>Для полноты картины хотелось бы отметить, что MethodBase.GetCurrentMethod также использует StackTrace, но поскольку это выполняется в native коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.
L>С чего вы взяли, что GetCurrentMethod использует StackTrace? Вот реализация, которую мне показывает Reflector:
Что приводит нас к "Sscli20\clr\src\vm\reflectioninvocation.cpp"
// Return the MethodInfo that represents the current method (two above this one)
FCIMPL1(MethodDesc*, RuntimeMethodHandle::GetCurrentMethod, StackCrawlMark* stackMark) {
CONTRACTL {
THROWS;
DISABLED(GC_TRIGGERS);
MODE_COOPERATIVE;
SO_TOLERANT;
}
CONTRACTL_END;
SkipStruct skip;
skip.pStackMark = stackMark;
skip.pMeth = 0;
HELPER_METHOD_FRAME_BEGIN_RET_0();
StackWalkFunctions(GetThread(), SkipMethods, &skip);
HELPER_METHOD_FRAME_END();
return skip.pMeth;
}
FCIMPLEND
И, далее, к "Sscli20\clr\src\vm\stackwalk.cpp"
StackWalkAction StackWalkFunctions(Thread * thread,
PSTACKWALKFRAMESCALLBACK pCallback,
VOID * pData)
{
// Note: there are cases (i.e., exception handling) where we may never return from this function. This means
// that any C++ destructors pushed in this function will never execute, and it means that this function can
// never have a dynamic contract.
STATIC_CONTRACT_WRAPPER;
return thread->StackWalkFrames(pCallback, pData, FUNCTIONSONLY);
}
Реализация "StackWalkFrames" находится там же в "Sscli20\clr\src\vm\stackwalk.cpp".
Это не совсем то же, что получается при использовании класса StackTrace, но так же "то ещё мясо".
Help will always be given at Hogwarts to those who ask for it.