Jak mogę znaleźć metodę, która wywołała bieżącą metodę?
Podczas logowania w C#, Jak mogę poznać nazwę metody, która wywołała bieżącą metodę? Wiem wszystko o System.Reflection.MethodBase.GetCurrentMethod()
, ale chcę przejść krok poniżej tego w ślad stosu. Rozważałem parsowanie śladów stosu, ale mam nadzieję znaleźć bardziej wyraźny sposób, coś w stylu Assembly.GetCallingAssembly()
, ale dla metod.
17 answers
Spróbuj tego:
using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
Pochodzi z Get wywołanie metody za pomocą Reflection [C#].
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-17 19:00:01
W C# 5 możesz uzyskać tę informację używając informacji o rozmówcy:
//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "")
{
Console.WriteLine(callerName + "called me.");
}
Można również uzyskać [CallerFilePath]
i [CallerLineNumber]
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-09 11:22:08
Możesz użyć informacji o rozmówcy i opcjonalnych parametrów:
public static string WhoseThere([CallerMemberName] string memberName = "")
{
return memberName;
}
Ten test ilustruje to:
[Test]
public void Should_get_name_of_calling_method()
{
var methodName = CachingHelpers.WhoseThere();
Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}
Podczas gdy StackTrace działa dość szybko powyżej i nie stanowi problemu z wydajnością w większości przypadków informacje o rozmówcy są znacznie szybsze. W próbce 1000 iteracji, taktowałem go 40 razy szybciej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 12:41:13
Ogólnie można użyć System.Diagnostics.StackTrace
Klasa aby dostać a System.Diagnostics.StackFrame
, a następnie użyj GetMethod()
metoda na uzyskanie System.Reflection.MethodBase
obiekt. Jednak istnieją pewne zastrzeżenia do tego podejścia:
- reprezentuje stos runtime -- optymalizacje mogą być wbudowane w metodę, a Ty będziesz nie zobacz tę metodę w śledzeniu stosu.
- będzie Nie Pokaż dowolne natywne ramki, więc jeśli jest choćby szansa twoja metoda jest wywoływana przez natywną metodę, będzie to Nie pracy, a w rzeczywistości nie ma na to obecnie dostępnego sposobu.
(Uwaga: właśnie rozszerzam ODPOWIEDŹ udzieloną przez Firas Assad.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:30
Możemy poprawić kod Pana Assada (obecna akceptowana odpowiedź) tylko trochę poprzez utworzenie tylko ramki, której faktycznie potrzebujemy, a nie całego stosu:
new StackFrame(1).GetMethod().Name;
Może to działać nieco lepiej, choć najprawdopodobniej nadal musi używać pełnego stosu do tworzenia pojedynczej klatki. Ponadto, nadal ma te same zastrzeżenia, które Alex Lyman wskazał (optymalizator / kod macierzysty może uszkodzić wyniki). Na koniec warto sprawdzić, czy new StackFrame(1)
lub .GetFrame(1)
nie return null
, tak mało prawdopodobne, jak mogłoby się to wydawać.
Zobacz to pytanie: Czy możesz użyć reflection, aby znaleźć nazwę aktualnie wykonywanej metody?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:01
Szybkie podsumowanie dwóch podejść z porównaniem prędkości jest ważną częścią.
Określenie wywołującego w czasie kompilacji
static void Log(object message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}
Określenie wywołującego za pomocą stosu
static void Log(object message)
{
// frame 1, true for source info
StackFrame frame = new StackFrame(1, true);
var method = frame.GetMethod();
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber();
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}
Porównanie 2 podejść
Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms
Więc widzisz, używanie atrybutów jest dużo, dużo szybsze! Prawie 25x w rzeczywistości szybciej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-23 10:43:51
od. NET 4.5 możesz używać informacji o rozmówcy atrybuty:
-
CallerFilePath
- Plik źródłowy wywołujący funkcję; -
CallerLineNumber
- linia kodu wywołująca funkcję; -
CallerMemberName
- członek, który wywołał funkcję.public void WriteLine( [CallerFilePath] string callerFilePath = "", [CallerLineNumber] long callerLineNumber = 0, [CallerMemberName] string callerMember= "") { Debug.WriteLine( "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", callerFilePath, callerLineNumber, callerMember); }
Ta funkcja jest również obecna w". NET Core "i". NET Standard".
Referencje
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 18:52:35
Zauważ, że robienie tego będzie zawodne w kodzie Wydania, ze względu na optymalizację. Dodatkowo uruchomienie aplikacji w trybie piaskownicy (udział sieciowy) w ogóle nie pozwoli na przechwycenie ramki stosu.
Rozważ programowanie zorientowane na aspekt (AOP), jak PostSharp , które zamiast być wywoływane z twojego kodu, modyfikuje Twój kod, a tym samym wie, gdzie on jest przez cały czas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-31 22:01:07
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
return GetCallingMethod("GetCallingMethod");
}
/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
string str = "";
try
{
StackTrace st = new StackTrace();
StackFrame[] frames = st.GetFrames();
for (int i = 0; i < st.FrameCount - 1; i++)
{
if (frames[i].GetMethod().Name.Equals(MethodAfter))
{
if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
{
str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
break;
}
}
}
}
catch (Exception) { ; }
return str;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-28 20:08:14
Oczywiście jest to późna odpowiedź, ale mam lepszą opcję, jeśli możesz użyć. NET 4.5 lub więcej:
internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}
Wyświetli bieżącą datę i godzinę, a następnie " Przestrzeń nazw.Nazwa klasy.MethodName "i kończące się na": text".
Przykładowe wyjście:
6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized
Użycie próbki:
Logger.WriteInformation<MainWindow>("MainWindow initialized");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-27 11:28:42
Może szukasz czegoś takiego:
StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name
MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-05 20:09:42
private static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
private static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
A fantastic class is here: http://www.csharp411.com/c-get-calling-method/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-04 18:40:54
Innym podejściem, które zastosowałem, jest dodanie parametru do danej metody. Na przykład zamiast void Foo()
użyj void Foo(string context)
. Następnie przekaż jakiś unikalny ciąg znaków, który wskazuje kontekst wywołania.
Jeśli potrzebujesz tylko rozmówcy / kontekstu do rozwoju, możesz usunąć param
przed wysyłką.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-16 11:18:38
Spójrz na Logowanie nazwy metody w. NET. uważaj na używanie go w kodzie produkcyjnym. StackFrame może nie być wiarygodne...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-17 19:03:22
Możemy również użyć lambda ' s, aby znaleźć rozmówcę.
Załóżmy, że masz zdefiniowaną przez siebie metodę:
public void MethodA()
{
/*
* Method code here
*/
}
/ Align = "left" /
1. Zmień sygnaturę metody, abyśmy mieli parametr typu Action (Func też będzie działać):
public void MethodA(Action helperAction)
{
/*
* Method code here
*/
}
2. Nazwy Lambda nie są generowane losowo. Reguła wydaje się być: > _ _ X gdzie CallerMethodName jest zastępowane przez poprzednią funkcję, A X jest indeks.
private MethodInfo GetCallingMethodInfo(string funcName)
{
return GetType().GetMethod(
funcName.Substring(1,
funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1)
);
}
3. Podczas wywołania metody parametr Action / Func musi zostać wygenerowany przez metodę wywołującą. Przykład:
MethodA(() => {});
4. Wewnątrz metody możemy teraz wywołać funkcję pomocniczą zdefiniowaną powyżej i znaleźć MethodInfo metody wywołującej.
Przykład:
MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-16 06:17:41
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;
Chyba wystarczy.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 08:20:41
var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-06 09:02:13