¿Puede usar reflexión para encontrar el nombre del método que se está ejecutando actualmente?


Como dice el título: ¿Puede la reflexión darle el nombre del método que se está ejecutando actualmente.

Me inclino a suponer que no, debido al problema de Heisenberg. ¿Cómo llamas a un método que te dirá el método actual sin cambiar cuál es el método actual? Pero espero que alguien pueda probar que me equivoco.

Actualización:

  • Parte 2: ¿Podría esto ser usado para buscar dentro del código de una propiedad también?
  • Parte 3: ¿Cuál sería la actuación ser como?

Resultado final
Aprendí sobre MethodBase.GetCurrentMethod(). También aprendí que no solo puedo crear un seguimiento de pila, sino que puedo crear solo el marco exacto que necesito si quiero.

Para usar esto dentro de una propiedad, simplemente tome a .Subcadena (4) para eliminar el 'set_' o 'get_'.

Author: Joel Coehoorn, 2008-09-04

13 answers

A partir de. NET 4.5 también puede usar [CallerMemberName]

Ejemplo: un setter de propiedades (para responder a la parte 2):

    protected void SetProperty<T>(T value, [CallerMemberName] string property = null)
    {
        this.propertyValues[property] = value;
        OnPropertyChanged(property);
    }

    public string SomeProperty
    {
        set { SetProperty(value); }
    }

El compilador suministrará literales de cadena coincidentes en los sitios de llamada, por lo que básicamente no hay sobrecarga de rendimiento.

 99
Author: John Nilsson,
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-01-24 22:15:23
 176
Author: Ed Guiness,
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-08-26 21:18:29

El fragmento proporcionado por Lex era un poco largo, así que estoy señalando la parte importante ya que nadie más usó exactamente la misma técnica:

string MethodName = new StackFrame(0).GetMethod().Name;

Esto debería devolver resultados idénticos a la técnica MethodBase.GetCurrentMethod().Name, pero todavía vale la pena señalar porque podría implementar esto una vez en su propio método usando índice 1 para el método anterior y llamarlo desde un número de propiedades diferentes. Además, solo devuelve un fotograma en lugar del traza de pila completa:

private string GetPropertyName()
{  //.SubString(4) strips the property prefix (get|set) from the name
    return new StackFrame(1).GetMethod().Name.Substring(4);
}

También es de una sola línea;)

 45
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
2008-11-12 15:53:51

Pruebe esto dentro del método Principal en un programa de consola vacío:

MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);

Salida de consola:
Main

 14
Author: Lars Mæhlum,
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-09-04 16:52:03

Sí, definitivamente.

Si quieres manipular un objeto en realidad uso una función como esta:

public static T CreateWrapper<T>(Exception innerException, params object[] parameterValues) where T : Exception, new()
{
    if (parameterValues == null)
    {
        parameterValues = new object[0];
    }

    Exception exception   = null;
    StringBuilder builder = new StringBuilder();
    MethodBase method     = new StackFrame(2).GetMethod();
    ParameterInfo[] parameters = method.GetParameters();
    builder.AppendFormat(CultureInfo.InvariantCulture, ExceptionFormat, new object[] { method.DeclaringType.Name, method.Name });
    if ((parameters.Length > 0) || (parameterValues.Length > 0))
    {
        builder.Append(GetParameterList(parameters, parameterValues));
    }

    exception = (Exception)Activator.CreateInstance(typeof(T), new object[] { builder.ToString(), innerException });
    return (T)exception;
}

Esta línea:

MethodBase method     = new StackFrame(2).GetMethod();

Camina por el marco de la pila para encontrar el método de llamada, luego usamos reflexión para obtener los valores de información de parámetros que se le pasan para una función genérica de informe de errores. Para obtener el método actual simplemente use current stack frame (1) en su lugar.

Como otros han dicho para el nombre de los métodos actuales, también puede usar:

MethodBase.GetCurrentMethod()

Prefiero caminar la pila porque si mirar internamente en ese método simplemente crea un StackCrawlMark de todos modos. Abordar la pila directamente me parece más claro

Post 4.5 ahora puede usar [CallerMemberNameAttribute] como parte de los parámetros del método para obtener una cadena del nombre del método - esto puede ayudar en algunos escenarios (pero realmente en decir el ejemplo anterior)

public void Foo ([CallerMemberName] string methodName = null)

Esto parecía ser principalmente una solución para el soporte INotifyPropertyChanged donde anteriormente había cadenas llenas de todo a través de tu código de evento.

 12
Author: Lex,
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-06-27 10:23:22

EDIT: MethodBase es probablemente una mejor manera de simplemente obtener el método en el que estás (en lugar de toda la pila de llamadas). Sin embargo, todavía me preocuparía por la inserción.

Puede usar una traza apilada dentro del método:

StackTrace st = new StackTrace(true);

Y la mirada a los marcos:

// The first frame will be the method you want (However, see caution below)
st.GetFrames();

Sin embargo, tenga en cuenta que si el método está inlineado, no estará dentro del método que cree que está. Puede usar un atributo para evitar la inserción:

[MethodImpl(MethodImplOptions.NoInlining)]
 9
Author: denis phillips,
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-09-04 16:52:40

Comparando formas de obtener el nombre del método using usando una construcción de tiempo arbitraria en LINQPad:

CÓDIGO

void Main()
{
    // from http://blogs.msdn.com/b/webdevelopertips/archive/2009/06/23/tip-83-did-you-know-you-can-get-the-name-of-the-calling-method-from-the-stack-using-reflection.aspx
    // and https://stackoverflow.com/questions/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code

    var fn = new methods();

    fn.reflection().Dump("reflection");
    fn.stacktrace().Dump("stacktrace");
    fn.inlineconstant().Dump("inlineconstant");
    fn.constant().Dump("constant");
    fn.expr().Dump("expr");
    fn.exprmember().Dump("exprmember");
    fn.callermember().Dump("callermember");

    new Perf {
        { "reflection", n => fn.reflection() },
        { "stacktrace", n => fn.stacktrace() },
        { "inlineconstant", n => fn.inlineconstant() },
        { "constant", n => fn.constant() },
        { "expr", n => fn.expr() },
        { "exprmember", n => fn.exprmember() },
        { "callermember", n => fn.callermember() },
    }.Vs("Method name retrieval");
}

// Define other methods and classes here
class methods {
    public string reflection() {
        return System.Reflection.MethodBase.GetCurrentMethod().Name;
    }
    public string stacktrace() {
        return new StackTrace().GetFrame(0).GetMethod().Name;
    }
    public string inlineconstant() {
        return "inlineconstant";
    }
    const string CONSTANT_NAME = "constant";
    public string constant() {
        return CONSTANT_NAME;
    }
    public string expr() {
        Expression<Func<methods, string>> ex = e => e.expr();
        return ex.ToString();
    }
    public string exprmember() {
        return expressionName<methods,string>(e => e.exprmember);
    }
    protected string expressionName<T,P>(Expression<Func<T,Func<P>>> action) {
        // https://stackoverflow.com/a/9015598/1037948
        return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name;
    }
    public string callermember([CallerMemberName]string name = null) {
        return name;
    }
}

RESULTADOS

Reflexión reflexión

Stacktrace stacktrace

Inlineconstant inlineconstant

Constante constante

Expr e = > e.expr ()

Exprmember exprmember

Callermember Main

Method name retrieval: (reflection) vs (stacktrace) vs (inlineconstant) vs (constant) vs (expr) vs (exprmember) vs (callermember) 

 154673 ticks elapsed ( 15.4673 ms) - reflection
2588601 ticks elapsed (258.8601 ms) - stacktrace
   1985 ticks elapsed (  0.1985 ms) - inlineconstant
   1385 ticks elapsed (  0.1385 ms) - constant
1366706 ticks elapsed (136.6706 ms) - expr
 775160 ticks elapsed ( 77.516  ms) - exprmember
   2073 ticks elapsed (  0.2073 ms) - callermember


>> winner: constant

Nota que los métodos expr y callermember no son del todo "correctos". Y ahí ven una repetición de un comentario relacionado que la reflexión es ~15 veces más rápida que stacktrace.

 9
Author: drzaus,
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:26:20

¿Qué tal esto 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
 4
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:11:13

La forma sencilla de tratar es:

System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;

Si el Sistema.La reflexión se incluye en el bloque using:

MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;
 4
Author: Shar,
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-14 19:04:12

Creo que deberías ser capaz de obtener eso creando un StackTrace. O, como @edg y @ Lars Mæhlum mencionan, MethodBase. GetCurrentMethod()

 2
Author: bdukes,
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:02:39

Si solo necesita el nombre de la cadena del método, puede usar Expresiones. Véase http://joelabrahamsson.com/entry/getting-property-and-method-names-using-static-reflection-in-c-sharp

 0
Author: awgtek,
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-10-02 13:46:44

Prueba esto...

    /// <summary>
    /// Return the full name of method
    /// </summary>
    /// <param name="obj">Class that calls this method (use Report(this))</param>
    /// <returns></returns>
    public string Report(object obj)
    {
        var reflectedType = new StackTrace().GetFrame(1).GetMethod().ReflectedType;
        if (reflectedType == null) return null;

        var i = reflectedType.FullName;
        var ii = new StackTrace().GetFrame(1).GetMethod().Name;

        return string.Concat(i, ".", ii);
    }
 0
Author: Adriano silva ribeiro,
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-12-29 06:52:21

Acabo de hacer esto con una clase estática simple:

using System.Runtime.CompilerServices;
.
.
.
    public static class MyMethodName
        {
            public static string Show([CallerMemberName] string name = "")
            {
                return name;
            }
        }

Luego en su código:

private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = MyMethodName.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = MyMethodName.Show();
        }
 0
Author: michael kosak,
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-08-09 14:52:29