Jak zalogować się w języku C #, jak mogę poznać nazwę metody, która wywołała bieżącą metodę? Wiem wszystko System.Reflection.MethodBase.GetCurrentMethod()
, ale chcę przejść o krok dalej w śladzie stosu. Zastanawiałem się nad parsowaniem śladu stosu, ale mam nadzieję znaleźć bardziej przejrzysty sposób, coś w rodzaju Assembly.GetCallingAssembly()
metod.
c#
.net
logging
stack-trace
system.diagnostics
flipdoubt
źródło
źródło
StackTrace
,StackFrame
iCallerMemberName
) i publikowane wyniki jako GIST, aby inni mogli zobaczyć tutaj: gist.github.com/wilson0x4d/7b30c3913e74adf4ad99b09163a57a1fOdpowiedzi:
Spróbuj tego:
jednowarstwowy:
Pochodzi z metody Get Calling Method przy użyciu Reflection [C #] .
źródło
W C # 5 możesz uzyskać te informacje za pomocą informacji o dzwoniącym :
Możesz także uzyskać
[CallerFilePath]
i[CallerLineNumber]
.źródło
[CallerTypeName]
został usunięty z obecnego frameworku .Net (4.6.2) i Core CLRMożesz użyć informacji o dzwoniącym i opcjonalnych parametrów:
Ten test ilustruje to:
Chociaż StackTrace działa dość szybko powyżej i w większości przypadków nie będzie to problem z wydajnością, informacje o dzwoniącym są nadal znacznie szybsze. W próbce 1000 iteracji taktowałem ją 40 razy szybciej.
źródło
CachingHelpers.WhoseThere("wrong name!");
==>,"wrong name!"
ponieważCallerMemberName
jest to tylko podstawia wartość domyślną.this
parametr do metody rozszerzenia. Ponadto Olivier ma rację, można przekazać wartość i[CallerMemberName]
nie jest ona stosowana; zamiast tego działa jako nadpisanie, w którym normalnie byłaby używana wartość domyślna. W rzeczywistości, jeśli spojrzymy na IL, zobaczymy, że uzyskana metoda nie różni się od tego, co normalnie byłoby emitowane dla[opt]
arg, wstrzyknięcieCallerMemberName
jest zatem zachowaniem CLR. Na koniec dokumenty: „Atrybuty informacji o abonencie wywołującym [...] wpływają na domyślną wartość, która jest przekazywana, gdy argument jest pominięty ”async
przyjazne, które ciStackFrame
nie pomoże. Nie wpływa również na wywołanie z lambda.Szybkie podsumowanie 2 podejść, przy czym ważnym elementem jest porównanie prędkości.
http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx
Określanie dzwoniącego w czasie kompilacji
Określanie dzwoniącego za pomocą stosu
Porównanie dwóch podejść
źródło
Możemy nieco ulepszyć kod pana Assada (obecna akceptowana odpowiedź), tworząc tylko potrzebną ramkę, a nie cały stos:
Może to działać nieco lepiej, choć najprawdopodobniej nadal musi użyć pełnego stosu, aby utworzyć tę pojedynczą ramkę. Ponadto nadal ma te same zastrzeżenia, które wskazał Alex Lyman (optymalizator / kod natywny może uszkodzić wyniki). Wreszcie możesz sprawdzić, aby upewnić się, że nie ,
new StackFrame(1)
lub.GetFrame(1)
nie powrócićnull
, tak mało prawdopodobne, jak mogłoby się wydawać.Zobacz to pokrewne pytanie: czy możesz użyć refleksji, aby znaleźć nazwę aktualnie wykonywanej metody?
źródło
new ClassName(…)
wynosi zero?Ogólnie rzecz biorąc, możesz użyć
System.Diagnostics.StackTrace
klasy, aby uzyskać aSystem.Diagnostics.StackFrame
, a następnie użyćGetMethod()
metody, aby uzyskaćSystem.Reflection.MethodBase
obiekt. Istnieją jednak pewne zastrzeżenia dotyczące tego podejścia:( UWAGA: Właśnie rozwijam odpowiedź udzieloną przez Firas Assad .)
źródło
Począwszy od .NET 4.5 można używać atrybutów informacji o dzwoniącym :
CallerFilePath
- Plik źródłowy, który wywołał funkcję;CallerLineNumber
- Wiersz kodu, który wywołał funkcję;CallerMemberName
- Członek, który wywołał funkcję.Ta funkcja jest również dostępna w „.NET Core” i „.NET Standard”.
Bibliografia
CallerFilePathAttribute
klasaCallerLineNumberAttribute
klasaCallerMemberNameAttribute
klasaźródło
Pamiętaj, że takie postępowanie będzie niewiarygodne w kodzie wersji ze względu na optymalizację. Ponadto uruchomienie aplikacji w trybie piaskownicy (udział sieciowy) w ogóle nie pozwala na uchwycenie ramki stosu.
Zastanów się nad programowaniem aspektowym (AOP), takim jak PostSharp , który zamiast być wywoływany z kodu, modyfikuje kod, a tym samym wie, gdzie on jest.
źródło
Oczywiście jest to późna odpowiedź, ale mam lepszą opcję, jeśli możesz używać .NET 4.5 lub więcej:
Spowoduje to wydrukowanie bieżącej daty i godziny, a następnie „Namespace.ClassName.MethodName” i kończące się na „: text”.
Przykładowe dane wyjściowe:
Przykładowe użycie:
źródło
źródło
Może szukasz czegoś takiego:
źródło
Fantastyczna klasa jest tutaj: http://www.csharp411.com/c-get-calling-method/
źródło
Innym podejściem, które zastosowałem, jest dodanie parametru do metody, o której mowa. Na przykład zamiast
void Foo()
użyjvoid Foo(string context)
. Następnie przekaż unikalny ciąg znaków, który wskazuje kontekst wywołania.Jeśli potrzebujesz tylko dzwoniącego / kontekstu do opracowania, możesz usunąć
param
przed wysyłką.źródło
Aby uzyskać nazwę metody i nazwę klasy, spróbuj:
źródło
myślę, że wystarczy.
źródło
Spójrz na nazwę metody rejestrowania w .NET . Uwaga na używanie go w kodzie produkcyjnym. StackFrame może nie być wiarygodny ...
źródło
Możemy również użyć lambda do znalezienia dzwoniącego.
Załóżmy, że masz zdefiniowaną przez siebie metodę:
i chcesz znaleźć dzwoniącego.
1 . Zmień podpis metody, abyśmy mieli parametr typu Action (Func również będzie działał):
2 . Nazwy Lambda nie są generowane losowo. Reguła wydaje się wyglądać następująco:> <nazwa_programu_wywołania> __X, gdzie nazwa_wywołania jest zastępowana przez poprzednią funkcję, a X to indeks.
3 . Kiedy wywołujemy MethodA, parametr Action / Func musi zostać wygenerowany przez metodę wywołującą. Przykład:
4 . Wewnątrz MethodA możemy teraz wywołać funkcję pomocniczą zdefiniowaną powyżej i znaleźć MethodInfo metody wywołującej.
Przykład:
źródło
Dodatkowe informacje do odpowiedzi Firas Assaad.
Użyłem
new StackFrame(1).GetMethod().Name;
w .net core 2.1 z iniekcją zależności i otrzymuję metodę wywoływania jako „Start”.Próbowałem z
[System.Runtime.CompilerServices.CallerMemberName] string callerName = ""
i daje mi to prawidłową metodę wywoływaniaźródło
źródło