¿Cómo puedo encontrar el método que llamó al método actual?


Al iniciar sesión en C#, ¿cómo puedo aprender el nombre del método que llamó al método actual? Sé todo sobre System.Reflection.MethodBase.GetCurrentMethod(), pero quiero ir un paso por debajo de esto en el seguimiento de la pila. He considerado analizar el seguimiento de la pila, pero espero encontrar una forma más clara y explícita, algo como Assembly.GetCallingAssembly() pero para los métodos.

Author: Shaun Wilson, 2008-10-05

17 answers

Prueba esto:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();

// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

Es de Get Calling Método usando Reflexión [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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-17 19:00:01

En C # 5 puedes obtener esa información usando la información del llamante:

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

También puedes obtener [CallerFilePath] y [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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-09 11:22:08

Puede utilizar la información de la persona que llama y los parámetros opcionales:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
       return memberName;
}

Esta prueba ilustra esto:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}

Mientras que el StackTrace funciona bastante rápido arriba y no sería un problema de rendimiento en la mayoría de los casos, la Información de la persona que Llama es mucho más rápida aún. En una muestra de 1000 iteraciones, lo registré como 40 veces más rápido.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-09 12:41:13

En general, puede utilizar el System.Diagnostics.StackTrace clase para obtener un System.Diagnostics.StackFrame, y luego utilizar el GetMethod() método para obtener una System.Reflection.MethodBase objeto. Sin embargo, hay algunas advertencias a este enfoque:

  1. Representa la pila runtime optim las optimizaciones podrían insertar un método, y no vea ese método en el seguimiento de pila.
  2. se no mostrar cualquier marcos nativos, así que si hay una posibilidad su método está siendo llamado por un método nativo, esto será no trabajo, y de hecho no hay una forma actualmente disponible para hacerlo.

(NOTA: Solo estoy expandiendo la respuesta proporcionada por 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:30

Podemos mejorar el código del Sr. Assad (la respuesta aceptada actual) solo un poco instanciando solo el marco que realmente necesitamos en lugar de toda la pila:

new StackFrame(1).GetMethod().Name;

Esto podría funcionar un poco mejor, aunque con toda probabilidad todavía tiene que usar la pila completa para crear ese marco único. Además, todavía tiene las mismas advertencias que Alex Lyman señaló (optimizador/código nativo podría corromper los resultados). Por último, es posible que desee comprobar para asegurarse de que new StackFrame(1) o .GetFrame(1) no return null, por improbable que parezca esa posibilidad.

Ver esta pregunta relacionada: ¿Puede usar reflexión para encontrar el nombre del método actualmente en ejecución?

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:01

Un resumen rápido de los 2 enfoques con la comparación de velocidad es la parte importante.

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

Determinando el llamante en tiempo de compilación

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);
}

Determinando el llamante usando la pila

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);
}

Comparación de los 2 enfoques

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

Así que ya ves, el uso de los atributos es mucho, mucho más rápido! Casi 25x más rápido de hecho.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-23 10:43:51

A partir de. NET 4.5 puede usar Información del llamante Atributos:

  • CallerFilePath - El archivo fuente que llamó a la función;
  • CallerLineNumber - Línea de código que llamó a la función;
  • CallerMemberName - Miembro que llamó a la función.

    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);
    }
    

 

Esta facilidad también está presente en". NET Core" y". NET Standard".

Referencias

  1. Microsoft - Información de la Persona Que Llama (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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-17 18:52:35

Tenga en cuenta que hacerlo será poco fiable en el código de lanzamiento, debido a la optimización. Además, ejecutar la aplicación en modo sandbox (recurso compartido de red) no le permitirá agarrar el marco de la pila en absoluto.

Considere la programación orientada a aspectos (AOP), como PostSharp, que en lugar de ser llamada desde su código, modifica su código, y por lo tanto sabe dónde está en todo momento.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-28 20:08:14

Obviamente esta es una respuesta tardía, pero tengo una mejor opción si puedes usar. NET 4.5 o más:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

Esto imprimirá la Fecha y Hora actuales, seguido de "Namespace.className.methodName "y terminando con": text".
Salida de muestra:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

Uso de la muestra:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-27 11:28:42

Tal vez usted está buscando algo como esto:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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;
}

Una clase fantástica está aquí: 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-04 18:40:54

Otro enfoque que he utilizado es agregar un parámetro al método en cuestión. Por ejemplo, en lugar de void Foo(), use void Foo(string context). Luego pase una cadena única que indique el contexto de llamada.

Si solo necesita el llamador/contexto para el desarrollo, puede eliminar el param antes de enviar.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-16 11:18:38

Echa un vistazo a Nombre del método de registro en. NET. Tenga cuidado de usarlo en el código de producción. StackFrame puede no ser confiable...

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-17 19:03:22

También podemos usar lambda para encontrar al llamante.

Supongamos que tiene un método definido por usted:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

Y quieres encontrar a su llamante.

1. Cambie la firma del método para que tengamos un parámetro de tipo Action (Func también funcionará):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2. Los nombres Lambda no se generan aleatoriamente. La regla parece ser: > __X donde CallerMethodName es reemplazado por la función anterior y X es un Indice.

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf("&gt;", 1, StringComparison.Ordinal) - 1)
              );
    }

3. Cuando llamamos a methodA, el parámetro Action/Func debe ser generado por el método que llama. Ejemplo:

MethodA(() => {});

4. Dentro de methodA ahora podemos llamar a la función helper definida anteriormente y encontrar el MethodInfo del método de llamada.

Ejemplo:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-16 06:17:41
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

Será suficiente, creo.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-06 09:02:13