Как узнать имя функции?
От: Аноним  
Дата: 01.03.09 14:44
Оценка:
В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?
имя функции
Re: Как узнать имя функции?
От: Pavel_Agurov Россия  
Дата: 01.03.09 14:48
Оценка: 2 (1)
Здравствуйте, Аноним, Вы писали:

А>В С++ я мог использовать макрос __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);
}
Как узнать имя функции?
От: Tissot Россия  
Дата: 01.03.09 14:56
Оценка:
#Имя: faq.dotnet.func_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#, поэтому возможно криво):


        static void TraceToConsole(string reportText)
        {
            StackTrace st = new StackTrace(0);
            string prevFuncName = st.GetFrame(st.FrameCount - 1).GetMethod().Name;
            Console.WriteLine("{0}(): {1}", prevFuncName, reportText);
        }
Re[2]: Как узнать имя функции?
От: Lloyd Россия  
Дата: 01.03.09 16:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Пока сделал так (только начал изучать C#, поэтому возможно криво):


Получение StackTrace-а — очень тяжелая операция. Используй MethodBase
Re[3]: Как узнать имя функции?
От: Аноним  
Дата: 01.03.09 17:11
Оценка:
L>Получение StackTrace-а — очень тяжелая операция. Используй MethodBase

Но тогда мне придется передавать дополнительный параметр в ф-ию логера?
Re: Может кто-нибудь поделиться идеей простого логера?
От: Аноним  
Дата: 01.03.09 19:15
Оценка:
Может кто-нибудь поделиться идеей простого логера, чтобы трассировались имена ф-ий и было несложно понять новичку?
Каждый раз передвать как параметр

Log(MethodBase.GetCurrentMethod().ToString(), "Log event");

довольно неудобно, а ничего лучшего я пока не знаю.
Re: Как узнать имя функции?
От: maxnk  
Дата: 01.03.09 21:10
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?


Почему бы не попробовать log4net? Потратите немного времени на его изучение сейчас, зато сэкономите много потом.
Там есть паттерн, который вам нужен (%M) — логирует имя метода, из которого произошел вызов.

Brainbench (C#, Java, Web, OO)
StackOverflow
Re: Как узнать имя функции?
От: _FRED_ Россия
Дата: 02.03.09 04:14
Оценка:
Здравствуйте, Аноним, Вы писали:

А>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?


Если требуется логирование многих разных по сути и природе методов, то хардкодить это в тело самих методов — очень плохая идея. Это как раз тот случай, когда можно с пользой применить аспекты (AOP).

Пример простого перехватчика можно посмотреть здесь
Автор: _FRED_
Дата: 23.12.08
. Он позволяет запротоколировать не только имя метода, но и значения параметров и возвращаемое значение.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Как узнать имя функции?
От: _FRED_ Россия
Дата: 02.03.09 04:19
Оценка:
Здравствуйте, maxnk, Вы писали:

А>>В С++ я мог использовать макрос __FUNCTION__, например для логера, а как это делается в C# ?

M>Почему бы не попробовать log4net? Потратите немного времени на его изучение сейчас, зато сэкономите много потом.
M>Там есть паттерн, который вам нужен (%M) — логирует имя метода, из которого произошел вызов.

А каким образом он узнаёт имя метода знаешь?
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Как узнать имя функции?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 02.03.09 04:32
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Пример простого перехватчика можно посмотреть здесь
Автор: _FRED_
Дата: 23.12.08
.


или в LoggingAspect из BLToolkit
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[3]: Как узнать имя функции?
От: maxnk  
Дата: 02.03.09 07:34
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>А каким образом он узнаёт имя метода знаешь?


Использует StackTrace:
LocationInfo.cs

Brainbench (C#, Java, Web, OO)
StackOverflow
Re[4]: Как узнать имя функции?
От: _FRED_ Россия
Дата: 02.03.09 07:57
Оценка:
Здравствуйте, maxnk, Вы писали:

_FR>>А каким образом он узнаёт имя метода знаешь?

M>Использует StackTrace:
M>LocationInfo.cs

Правильно, со всеми вытекающими
Автор: Lloyd
Дата: 01.03.09
.
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 коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.
Re[5]: Как узнать имя функции?
От: maxnk  
Дата: 02.03.09 08:17
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Правильно, со всеми вытекающими
Автор: Lloyd
Дата: 01.03.09
.


Тут, я думаю, можно пожертвовать немного производительности во имя удобств, предоставляемых log4net.
Обычно логгинг в production включен только на сообщения уровня ERROR (причем, чаще всего это обработка исключений) и все, что имеет более низкий уровень, просто пропускается. Соответственно, StackTrace достаточно редко будет использоваться.

Ну конечно, если нужно логировать что-то постоянно и много, то другие варианты нужно использовать.

Brainbench (C#, Java, Web, OO)
StackOverflow
Re[4]: Как узнать имя функции?
От: Lloyd Россия  
Дата: 02.03.09 09:46
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Для полноты картины хотелось бы отметить, что MethodBase.GetCurrentMethod также использует StackTrace, но поскольку это выполняется в native коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.


С чего вы взяли, что GetCurrentMethod использует StackTrace? Вот реализация, которую мне показывает Reflector:
[MethodImpl(MethodImplOptions.NoInlining)]
public static MethodBase GetCurrentMethod()
{
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller);
}

Как видите, никакого упоминания StackTrace-а и в помине нет.
Re[5]: Как узнать имя функции?
От: Аноним  
Дата: 02.03.09 11:03
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>С чего вы взяли, что GetCurrentMethod использует StackTrace? Вот реализация, которую мне показывает Reflector:

L>
L>[MethodImpl(MethodImplOptions.NoInlining)]
L>public static MethodBase GetCurrentMethod()
L>{
L>    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
L>    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller);
L>}
L>

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 может неожиданно повлиять на производительность, в случае интенсивного использования в многопоточном приложении.
Re[5]: Как узнать имя функции?
От: _FRED_ Россия
Дата: 02.03.09 11:10
Оценка:
Здравствуйте, Lloyd, Вы писали:

А>>Для полноты картины хотелось бы отметить, что MethodBase.GetCurrentMethod также использует StackTrace, но поскольку это выполняется в native коде, возможно это будет быстрей (ну и в любом случае правильней — помним об инлайнинге.


L>С чего вы взяли, что GetCurrentMethod использует StackTrace? Вот реализация, которую мне показывает Reflector:

L>[MethodImpl(MethodImplOptions.NoInlining)]
L>public static MethodBase GetCurrentMethod()
L>{
L>    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
L>    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller);
L>}

L>Как видите, никакого упоминания StackTrace-а и в помине нет.

Путешествуем рефлектором дальше и приходим к вызову

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe void* _GetCurrentMethod(ref StackCrawlMark stackMark);


Теперь нам понадобится SSCLI. В "Sscli20\clr\src\vm\ecall.cpp" находим:
FCFuncElement("_GetCurrentMethod", RuntimeMethodHandle::GetCurrentMethod)


Что приводит нас к "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.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.