Can you use reflection to find the name of the currently executing method?
Asked Answered
S

19

218

Like the title says: Can reflection give you the name of the currently executing method.

I'm inclined to guess not, because of the Heisenberg problem. How do you call a method that will tell you the current method without changing what the current method is? But I'm hoping someone can prove me wrong there.

Update:

  • Part 2: Could this be used to look inside code for a property as well?
  • Part 3: What would the performance be like?

Final Result
I learned about MethodBase.GetCurrentMethod(). I also learned that not only can I create a stack trace, I can create only the exact frame I need if I want.

To use this inside a property, just take a .Substring(4) to remove the 'set_' or 'get_'.

Swastika answered 4/9, 2008 at 16:45 Comment(3)
Joel, I know its an old question, but what do you mean by creating exact frame of a method?Spenser
It refers to a specific item in the call stack: the portion of the stack trace that matters.Swastika
For async methods you can use GetMethodContextName() from Using System.Reflection to Get a Method's Full NameFairing
L
135

As of .NET 4.5, you can also use [CallerMemberName].

Example: a property setter (to answer part 2):

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

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

The compiler will supply matching string literals at call sites, so there is basically no performance overhead.

Liebman answered 9/3, 2013 at 11:18 Comment(8)
This is great! I was using the StackFrame(1) method described in other answers for logging, which seemed to work until the Jitter decided to start inlining things. I did not want to add the attribute to prevent inlining for performance reasons. Using the [CallerMemberName] approach fixed the issue. Thanks!Lavinia
[CallerMemberName] is availably at net 4 with the BCL build packedVeda
Take into account that using StackFrame(1) in debug mode should work. But when using release mode when compiling, there might be some optimizations and the stack may not be what you expect.Concavity
Won't this return the calling member (i.e. SomeProperty), instead of the currently executing method?Lashandralashar
Yes, invoking the setter will result in a call to OnPropertyChanged("SomeProperty") and not OnPropertyChanged("SetProperty")Liebman
Documentation linkWigging
This is as good a solution as you can get, but you need to remember that this won't necessarily return the answer you expect in release builds unless you disable JIT method inlining.Juggernaut
@Juggernaut I think the answer and first comment already made it clear that the solution is not impacted by JIT inlining.Stodge
K
199

For non-async methods one can use

System.Reflection.MethodBase.GetCurrentMethod().Name;

https://learn.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getcurrentmethod

Please remember that for async methods it will return "MoveNext".

Kriegspiel answered 4/9, 2008 at 16:51 Comment(6)
Be aware that this doesn't always yield the expected results. I.e., small methods or properties are often inlined in release builds, in which case the result will be the caller's method name instead.Middlings
As far as I know, no. Because in runtime, the MSIL is not available anymore from the execution pointer (it's JITted). You can still use reflection if you know the name of the method. The point is, when inlined, the currently executing method is now another method (i.e., one or more higher up the stack). In other words, the method disappeared. Even if you mark your method with NoInlining, there's still a chance it gets tail-call optimized, in which case it's gone too. It will work, however, while in debug build.Middlings
In order to avoid inline add [MethodImpl(MethodImplOptions.NoInlining)] attribute on top of the method.Holiness
Inside async method you will most likely get "MoveNext" as method name.Manslaughter
Is there a way to get the current method name of an async method?Veteran
@AlexanderRyanBaggett, consider to use GetCurrentMethodFullName as suggested in https://mcmap.net/q/20930/-using-system-reflection-to-get-a-method-39-s-full-name. It works for async most of times(but not always)Fairing
L
135

As of .NET 4.5, you can also use [CallerMemberName].

Example: a property setter (to answer part 2):

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

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

The compiler will supply matching string literals at call sites, so there is basically no performance overhead.

Liebman answered 9/3, 2013 at 11:18 Comment(8)
This is great! I was using the StackFrame(1) method described in other answers for logging, which seemed to work until the Jitter decided to start inlining things. I did not want to add the attribute to prevent inlining for performance reasons. Using the [CallerMemberName] approach fixed the issue. Thanks!Lavinia
[CallerMemberName] is availably at net 4 with the BCL build packedVeda
Take into account that using StackFrame(1) in debug mode should work. But when using release mode when compiling, there might be some optimizations and the stack may not be what you expect.Concavity
Won't this return the calling member (i.e. SomeProperty), instead of the currently executing method?Lashandralashar
Yes, invoking the setter will result in a call to OnPropertyChanged("SomeProperty") and not OnPropertyChanged("SetProperty")Liebman
Documentation linkWigging
This is as good a solution as you can get, but you need to remember that this won't necessarily return the answer you expect in release builds unless you disable JIT method inlining.Juggernaut
@Juggernaut I think the answer and first comment already made it clear that the solution is not impacted by JIT inlining.Stodge
S
51

The snippet provided by Lex was a little long, so I'm pointing out the important part since no one else used the exact same technique:

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

This should return identical results to the MethodBase.GetCurrentMethod().Name technique, but it's still worth pointing out because I could implement this once in its own method using index 1 for the previous method and call it from a number of different properties. Also, it only returns one frame rather then the entire stack trace:

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

It's a one-liner, too ;)

Swastika answered 4/9, 2008 at 17:18 Comment(4)
can be public static string GetPropertyName() in a helper class ? static method ?Miramirabeau
Same as with Ed Guiness's answer: the stack can be different in release builds and the first method may not be the same as the current method in cases of inlining or tail call optimization.Middlings
See John Nilsson's answer for a nice way around the inlining issue if you are using .Net 4.5.Lavinia
this could be better than accepted answer and above answer tooSusian
W
19

Try this inside the Main method in an empty console program:

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

Console Output:
Main

Wilderness answered 4/9, 2008 at 16:52 Comment(0)
W
18

Comparing ways to get the method name -- using an arbitrary timing construct in LinqPad:

CODE

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://mcmap.net/q/20931/-how-to-get-the-name-of-the-current-method-from-code-duplicate

    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://mcmap.net/q/20932/-extract-method-name-from-expression-tree
        return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name;
    }
    public string callermember([CallerMemberName]string name = null) {
        return name;
    }
}

RESULTS

reflection reflection

stacktrace stacktrace

inlineconstant inlineconstant

constant constant

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

Note that the expr and callermember methods aren't quite "right". And there you see a repetition of a related comment that reflection is ~15x faster than stacktrace.

Wivina answered 22/1, 2014 at 22:34 Comment(0)
S
12

Yes definitely.

If you want an object to manipulate I actually use a function like this:

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

This line:

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

Walks up the stack frame to find the calling method then we use reflection to obtain parameter information values passed to it for a generic error reporting function. To get the current method simply use current stack frame (1) instead.

As others have said for the current methods name you can also use:

MethodBase.GetCurrentMethod()

I prefer walking the stack because if look internally at that method it simply creates a StackCrawlMark anyway. Addressing the Stack directly seems clearer to me

Post 4.5 you can now use the [CallerMemberNameAttribute] as part of the method parameters to get a string of the method name - this may help in some scenarios (but really in say the example above)

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

This seemed to be mainly a solution for INotifyPropertyChanged support where previously you had strings littered all through your event code.

Subtractive answered 4/9, 2008 at 16:50 Comment(3)
Not silly; I simply passed them in. You could probably do something to make it more simple to look at but the effort to reward ratio seemed to favour keeping it simple. Essentially the dev just copies in the parameter list of the method signature (removing types of course).Subtractive
what it is: ExceptionFormat and GetParameterList?Miramirabeau
Way late in the reply but: ExceptionFormat is a constant string format and GetParameterList is a simply function that formats the parameters with the values (you could do this inline)Subtractive
B
9

EDIT: MethodBase is probably a better way to just get the method you're in (as opposed to the whole calling stack). I'd still be concerned about inlining however.

You can use a StackTrace within the method:

StackTrace st = new StackTrace(true);

And the look at the frames:

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

However, be aware that if the method is inlined, you will not be inside the method you think you are. You can use an attribute to prevent inlining:

[MethodImpl(MethodImplOptions.NoInlining)]
Basidiospore answered 4/9, 2008 at 16:52 Comment(2)
Inline due to Release optimization is especially tricky since the code will behave differently in Debug and Release configurations. Watch out for small properties, they are the most likely victims of this.Mislay
I wonder why woud you use new StackTrace(true) instead of new StackTrace(false). Setting that to true will cause the stack trace to atttempt capturing the file name, line number and etc, which might make this call slower. Otherwise, a nice answerBraunstein
O
8

The simple way to deal is:

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

If the System.Reflection is included in the using block:

MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;
Oncoming answered 8/10, 2015 at 15:50 Comment(0)
C
7

For Async Methods, you can use:

//using System.Reflection;

var myMethodName = MethodBase
                    .GetCurrentMethod()
                    .DeclaringType
                    .Name
                    .Substring(1)
                    .Split('>')[0];
Camarillo answered 3/5, 2021 at 16:21 Comment(1)
Similar implementation that supports normal and async methods is described in stackoverflow.com/questions/2968352/…Fairing
K
5

A bit more resilient, solution for customers from 2021,2022,2023:

namespace my {
   public struct notmacros
   {

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string 
  whoami( [CallerMemberName] string caller_name = null)
  {
     if (string.IsNullOrEmpty(caller_name)) 
        return "unknown";
     if (string.IsNullOrWhiteSpace(caller_name)) 
        return "unknown";
     return caller_name;
  }
 }
} // my namespace

Usage

using static my.notmacros
 // somewhere  appropriate
 var my_name = whoami() ;

.NET fiddle link for the actual demo:

https://dotnetfiddle.net/moK73n

Please note the compiler requirement: .NET 6 or better.

Klute answered 30/3, 2021 at 10:57 Comment(0)
M
4

How about this:

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
Mclyman answered 5/10, 2008 at 20:11 Comment(0)
G
4

To handle both async and plain old method calls, I did this.

In my application, it's only getting called from exception handlers, so perf is not a concern.

[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCurrentMethodName()
{
    var st = new StackTrace();
    var sf = st.GetFrame(1);
    string name = sf.GetMethod().Name;

    if (name.Equals("MoveNext"))
    {
        // We're inside an async method
        name = sf.GetMethod().ReflectedType.Name
                 .Split(new char[] { '<', '>' }, StringSplitOptions.RemoveEmptyEntries)[0];
    }

    return name;
}
Gasiform answered 24/6, 2021 at 20:19 Comment(0)
S
2

I think you should be able to get that from creating a StackTrace. Or, as @edg and @Lars Mæhlum mention, MethodBase.GetCurrentMethod()

Steno answered 4/9, 2008 at 16:48 Comment(0)
P
2

I just did this with a simple static class:

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

then in your code:

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

private void button2_Click(object sender, EventArgs e)
{
    textBox1.Text = MyMethodName.Show();
}
Periwig answered 9/8, 2017 at 14:52 Comment(0)
A
2
using System;
                    
public class Program
{
    public static void Main()
    {
        
        Console.WriteLine("1: {0} {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
        OtherMethod();
    }
    
    public static void OtherMethod()
    {
        Console.WriteLine("2: {0} {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
    }
}

Output:

1: Main Program
2: OtherMethod Program
Aerostatics answered 9/7, 2020 at 8:37 Comment(0)
R
1

Add this method somewhere and call it without parameter!

public static string GetCurrentMethodName([System.Runtime.CompilerServices.CallerMemberName] string name = "")
{
    return name;
}
Rhyton answered 18/9, 2020 at 5:45 Comment(0)
P
0

Try this...

    /// <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);
    }
Photoactive answered 29/12, 2015 at 6:40 Comment(0)
L
0

Here is what I'm using in a static helper class for my async methods.

public static string GetMethodName(string rawName)
{
    return rawName.Substring(1, rawName.IndexOf('>') - 1);
}

Calling it:

  string methodName = StringExtensionMethods.GetMethodName(MethodBase.GetCurrentMethod().ReflectedType.Name ?? "");

HTH

Ligula answered 21/2, 2023 at 17:49 Comment(0)
G
-1
new StackTrace().ToString().Split("\r\n",StringSplitOptions.RemoveEmptyEntries)[0].Replace("at ","").Trim()
Gothurd answered 16/8, 2019 at 15:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.