Reputation: 416131
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:
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_'.
Upvotes: 219
Views: 79075
Reputation: 1018
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.
Upvotes: 5
Reputation: 472
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
Upvotes: 0
Reputation: 3357
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;
}
Upvotes: 5
Reputation: 3116
For Async
Methods, you can use:
//using System.Reflection;
var myMethodName = MethodBase
.GetCurrentMethod()
.DeclaringType
.Name
.Substring(1)
.Split('>')[0];
Upvotes: 11
Reputation: 7958
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
Upvotes: 4
Reputation: 41
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();
}
Upvotes: 2
Reputation: 17307
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.
Upvotes: 137
Reputation: 97
Add this method somewhere and call it without parameter!
public static string GetCurrentMethodName([System.Runtime.CompilerServices.CallerMemberName] string name = "")
{
return name;
}
Upvotes: 1
Reputation: 1126
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
Upvotes: 2
Reputation: 437
new StackTrace().ToString().Split("\r\n",StringSplitOptions.RemoveEmptyEntries)[0].Replace("at ","").Trim()
Upvotes: -1
Reputation: 35287
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".
Upvotes: 200
Reputation: 2215
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;
Upvotes: 8
Reputation: 103
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);
}
Upvotes: 0
Reputation: 25034
Comparing ways to get the method name -- using an arbitrary timing construct in LinqPad:
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;
}
}
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.
Upvotes: 20
Reputation: 658
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.
Upvotes: 12
Reputation: 416131
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 ;)
Upvotes: 51
Reputation: 156055
I think you should be able to get that from creating a StackTrace. Or, as @edg and @Lars Mæhlum mention, MethodBase.GetCurrentMethod()
Upvotes: 2
Reputation: 12780
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)]
Upvotes: 9
Reputation: 6102
Try this inside the Main method in an empty console program:
MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);
Console Output:
Main
Upvotes: 19