Pregunta

Al iniciar sesión en C#, ¿cómo puedo saber el nombre del método que llamó al método actual?lo se 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 limpia y explícita, algo como Assembly.GetCallingAssembly() sino por métodos.

¿Fue útil?

Solución

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 Obtener método de llamada usando Reflection [C #] .

Otros consejos

En C# 5 puedes obtener esa información usando la información de la persona que llama:

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

También puedes conseguir el [CallerFilePath] y [CallerLineNumber].

Puede usar 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"));
}

Si bien 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 sincronicé 40 veces más rápido.

Podemos mejorar el código del Sr. Assad (la respuesta actual aceptada) solo un poco creando instancias 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ó (el optimizador / código nativo podría corromper los resultados). Finalmente, es posible que desee verificar para asegurarse de que new StackFrame(1) o .GetFrame(1) no devuelven null, por improbable que pueda parecer esa posibilidad.

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

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

  1. Representa la pila runtime : las optimizaciones podrían incorporar un método, y usted not verá ese método en el seguimiento de la pila.
  2. not mostrará cuadros nativos, por lo que si existe la posibilidad de que su método sea invocado por un método nativo, esto no trabajo, y de hecho no hay una forma disponible de hacerlo actualmente.

( NOTA: solo estoy expandiendo en la respuesta proporcionada por Firas Assad .)

Una recapitulación rápida de los 2 enfoques con la comparación de velocidad como parte importante.

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

Determinación de la persona que llama 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);
}

Determinación de la persona que llama 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, ¡usar los atributos es mucho, mucho más rápido! Casi 25x   más rápido de hecho.

A partir de .NET 4.5 puede usar Información de la persona que llama Atributos:

  • CallerFilePath - La fuente archivo 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);
    }
    

& nbsp;

Esta función también está presente en " .NET Core " y " .NET Standard " ;.

Referencias

  1. Microsoft - Información de la persona que llama (C #)
  2. Microsoft - CallerFilePathAttribute Clase
  3. Microsoft - CallerLineNumberAttribute Clase
  4. Microsoft - CallerMemberNameAttribute Clase

Tenga en cuenta que hacerlo no será confiable 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á tomar el marco de la pila en absoluto.

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

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

Obviamente esta es una respuesta tardía, pero tengo una mejor opción si puede 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 " ;: texto " ;.
Salida de muestra:

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

Ejemplo de uso:

Logger.WriteInformation<MainWindow>("MainWindow initialized");

Quizás estés 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
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 /

Otro enfoque que he usado 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 la llamada.

Si solo necesita la persona que llama / contexto para el desarrollo, puede eliminar el param antes del envío.

StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

será suficiente, creo.

Eche 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 ...

También podemos usar lambda para encontrar la persona que llama.

Suponga que tiene un método definido por usted:

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

y desea encontrar su interlocutor.

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

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

2 . Los nombres lambda no se generan al azar. La regla parece ser: & Gt; < CallerMethodName > __ X donde CallerMethodName se reemplaza por la función anterior y X es un índice.

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

3 . Cuando llamamos al Método A, el parámetro llamador debe generar el parámetro Acción / Func. Ejemplo:

MethodA(() => {});

4 . Dentro del Método A ahora podemos llamar a la función auxiliar definida anteriormente y encontrar el Método de Información del método de llamada.

Ejemplo:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

Para obtener el nombre del método y el nombre de la clase, intente esto:

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }

Información adicional a la respuesta de Firas Assaad.

He usado new StackFrame(1).GetMethod().Name; en .net core 2.1 con inyección de dependencia y obtengo el método de llamada como 'Inicio'.

Intenté con [System.Runtime.CompilerServices.CallerMemberName] string callerName = "" y me da el método de llamada correcto

var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top