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_'.
For non-async
methods one can use
System.Reflection.MethodBase.GetCurrentMethod().Name;
https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getcurrentmethod
Please remember that for async
methods it will return "MoveNext".
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.
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!
OnPropertyChanged("SomeProperty")
and not OnPropertyChanged("SetProperty")
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 ;)
Try this inside the Main method in an empty console program:
MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);
Console Output:
Main
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.
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.
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)]
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
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;
For Async
Methods, you can use:
//using System.Reflection;
var myMethodName = MethodBase
.GetCurrentMethod()
.DeclaringType
.Name
.Substring(1)
.Split('>')[0];
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
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;
}
A bit more resilient, solution for customers from 2021,2022:
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
I think you should be able to get that from creating a StackTrace. Or, as @edg and @Lars Mæhlum mention, MethodBase.GetCurrentMethod()
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
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();
}
Add this method somewhere and call it without parameter!
public static string GetCurrentMethodName([System.Runtime.CompilerServices.CallerMemberName] string name = "")
{
return name;
}
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);
}
new StackTrace().ToString().Split("\r\n",StringSplitOptions.RemoveEmptyEntries)[0].Replace("at ","").Trim()
Success story sharing
async
method you will most likely get "MoveNext" as method name.