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.

Author: Shaun Wilson, 2008-10-05

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#].

 403
Author: Firas Assaad,
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].

 267
Author: Coincoin,
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.

 87
Author: dove,
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:

  1. reprezentuje stos runtime -- optymalizacje mogą być wbudowane w metodę, a Ty będziesz nie zobacz tę metodę w śledzeniu stosu.
  2. 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.)

 57
Author: Alex Lyman,
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?

 55
Author: Joel Coehoorn,
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ą.

Http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

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.

 51
Author: Tikall,
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

  1. Microsoft - Informacje O Rozmówcy (C#)
  2. Microsoft - CallerFilePathAttribute Class
  3. Microsoft - CallerLineNumberAttribute Class
  4. Microsoft - CallerMemberNameAttribute Class
 14
Author: Ivan Pinto,
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.

 13
Author: Lasse Vågsæther Karlsen,
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;
}
 8
Author: Flanders,
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");
 8
Author: Camilo Terevinto,
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
 6
Author: jesal,
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/

 4
Author: Tebo,
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ą.

 2
Author: GregUzelac,
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...

 1
Author: Yuval Peled,
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("&gt;", 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);
 1
Author: smiron,
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.
 0
Author: caner,
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;
 -1
Author: Mauro Sala,
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