217

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_'.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794

19 Answers19

197

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

Victor Yarema
  • 1,183
  • 13
  • 15
Ed Guiness
  • 34,602
  • 16
  • 110
  • 145
  • 8
    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. – Abel Mar 02 '12 at 16:05
  • 5
    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. – Abel Mar 04 '12 at 12:33
  • 1
    In order to avoid inline add [MethodImpl(MethodImplOptions.NoInlining)] attribute on top of the method. –  Sep 07 '18 at 15:44
  • 2
    Inside `async` method you will most likely get "MoveNext" as method name. – Victor Yarema Jan 17 '20 at 14:17
  • Is there a way to get the current method name of an async method? – Alexander Ryan Baggett Sep 24 '20 at 15:13
  • @AlexanderRyanBaggett, consider to use GetCurrentMethodFullName as suggested in https://stackoverflow.com/a/48758173/52277. It works for async most of times(but not always) – Michael Freidgeim Aug 09 '22 at 10:23
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.

Pang
  • 9,564
  • 146
  • 81
  • 122
John Nilsson
  • 17,001
  • 8
  • 32
  • 42
  • 4
    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! – Brian Rogers Apr 04 '13 at 20:07
  • 5
    [CallerMemberName] is availably at net 4 with the [BCL build packed](http://www.nuget.org/packages/Microsoft.Bcl/1.0.19) – Venson Aug 04 '13 at 16:52
  • 2
    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. – Axel O'Connell May 27 '15 at 11:03
  • Won't this return the calling member (i.e. SomeProperty), instead of the currently executing method? – Lennart Aug 12 '16 at 08:09
  • 1
    Yes, invoking the setter will result in a call to `OnPropertyChanged("SomeProperty")` and not `OnPropertyChanged("SetProperty")` – John Nilsson Aug 14 '16 at 12:12
  • [Documentation link](https://msdn.microsoft.com/en-us/library/hh534540(v=vs.110).aspx) – Christopher Stevenson Nov 21 '16 at 19:59
  • 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. – Cirelli94 Sep 13 '18 at 07:41
  • @Cirelli94 I think the answer and first comment already made it clear that the solution is not impacted by JIT inlining. – Lingxi Jul 08 '21 at 01:55
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 ;)

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • can be public static string GetPropertyName() in a helper class ? static method ? – Kiquenet Jun 13 '11 at 12:22
  • 2
    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. – Abel Mar 02 '12 at 16:07
  • See John Nilsson's answer for a nice way around the inlining issue if you are using .Net 4.5. – Brian Rogers Apr 04 '13 at 20:16
  • this could be better than accepted answer and above answer too – T.Todua Sep 27 '17 at 18:26
19

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

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

Console Output:
Main

Lars Mæhlum
  • 6,074
  • 3
  • 28
  • 32
16

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

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.

Community
  • 1
  • 1
drzaus
  • 24,171
  • 16
  • 142
  • 201
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.

Lex
  • 658
  • 4
  • 17
  • 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). – Lex Jan 26 '11 at 15:52
  • what it is: ExceptionFormat and GetParameterList? – Kiquenet Sep 01 '11 at 11:41
  • 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) – Lex Jun 27 '13 at 10:08
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)]
denis phillips
  • 12,550
  • 5
  • 33
  • 47
  • 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. – DK. Jun 20 '11 at 14:45
  • 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 answer – Ivaylo Slavov May 09 '15 at 14:06
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;
Sunny Patel
  • 7,830
  • 2
  • 31
  • 46
SharK
  • 2,155
  • 1
  • 20
  • 28
6

For Async Methods, you can use:

//using System.Reflection;

var myMethodName = MethodBase
                    .GetCurrentMethod()
                    .DeclaringType
                    .Name
                    .Substring(1)
                    .Split('>')[0];
Useme Alehosaini
  • 2,998
  • 6
  • 18
  • 26
  • 1
    Similar implementation that supports normal and async methods is described in https://stackoverflow.com/questions/2968352/using-system-reflection-to-get-a-methods-full-name/48758173#48758173 – Michael Freidgeim Jun 22 '21 at 13:17
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.

Chef Gladiator
  • 902
  • 11
  • 23
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
Pang
  • 9,564
  • 146
  • 81
  • 122
jesal
  • 7,852
  • 6
  • 50
  • 56
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;
}
Paul Williams
  • 3,099
  • 38
  • 34
2

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

Community
  • 1
  • 1
bdukes
  • 152,002
  • 23
  • 148
  • 175
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();
}
Pang
  • 9,564
  • 146
  • 81
  • 122
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
mr R
  • 997
  • 2
  • 12
  • 25
1

Add this method somewhere and call it without parameter!

public static string GetCurrentMethodName([System.Runtime.CompilerServices.CallerMemberName] string name = "")
{
    return name;
}
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);
    }
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

Jeff Blumenthal
  • 442
  • 6
  • 8
-1
new StackTrace().ToString().Split("\r\n",StringSplitOptions.RemoveEmptyEntries)[0].Replace("at ","").Trim()
David Buck
  • 3,752
  • 35
  • 31
  • 35