76

I have a method in an object that is called from a number of places within the object. Is there a quick and easy way to get the name of the method that called this popular method.

Pseudo Code EXAMPLE:

public Main()
{
     PopularMethod();
}

public ButtonClick(object sender, EventArgs e)
{
     PopularMethod();
}

public Button2Click(object sender, EventArgs e)
{
     PopularMethod();
}

public void PopularMethod()
{
     //Get calling method name
}

Within PopularMethod() I would like to see the value of Main if it was called from Main ... I'd like to see "ButtonClick" if PopularMethod() was called from ButtonClick

I was looking at the System.Reflection.MethodBase.GetCurrentMethod() but that won't get me the calling method. I've looked at the StackTrace class but I really didn't relish running an entire stack trace every time that method is called.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574

7 Answers7

209

In .NET 4.5 / C# 5, this is simple:

public void PopularMethod([CallerMemberName] string caller = null)
{
     // look at caller
}

The compiler adds the caller's name automatically; so:

void Foo() {
    PopularMethod();
}

will pass in "Foo".

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 6
    What are the performance consequences of this solution? – Feckmore Jan 16 '13 at 19:12
  • 9
    @Feckmore none whatsoever : the compiler adds it as a literal during compilation. It will be signifantly faster than anything like looking at StackTrace etc. basically it gets compiled as PopularMethod("CurrentMethodName") – Marc Gravell Jan 16 '13 at 20:27
  • I get an error saying Cannot find CallerMemberName. VS Express C# 2010 – john k Feb 21 '14 at 03:04
  • @user396483 you need to be targeting .NET 4.5 or above for the attribute to exist (although you can define it yourself), and you need to be using C# 5 for it to work in the way desired. VS Express 2013 is available and free – Marc Gravell Feb 21 '14 at 08:48
82

I don't think it can be done without tracing the stack. However, it's fairly simple to do that:

StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
Console.WriteLine(methodBase.Name); // e.g.

However, I think you really have to stop and ask yourself if this is necessary.

jason
  • 236,483
  • 35
  • 423
  • 525
  • For more info see: http://discuss.joelonsoftware.com/default.asp?dotnet.12.511358.10 – Eric Lathrop Mar 05 '09 at 18:35
  • 4
    System.Diagnostics is the namespace of StackTrace, System.Reflection is the namespace of MethodBase. – Guvante Mar 05 '09 at 18:35
  • 1
    Jason - Thank you, I'm not sure how resource intensive the "StackTrace" method is, but this does get me what I'm looking for. This is just a debugging code block for me, this won't be going into production. Thank you again for your help ! –  Mar 05 '09 at 18:35
  • This has code smell to me; maybe there's some issues with your OO design here that make you want to see who called your method. In that case maybe you've got a polymorphism break? – jcollum Mar 05 '09 at 18:36
  • 2
    @Scott Vercuski - It's an immensly expensive operation, if there's any way you can avoid this you really should. It way worse than throwing exceptions and that's bad. It's nice that it can be done, but it should not be misused. – John Leidegren Mar 06 '09 at 05:47
  • 1
    @John Leidegren - Definitely ... this isn't going into production code, we're just doing some massive QA testing and getting some strange happenings, this is just to help figure out where things are going haywire. Thank you ! –  Mar 06 '09 at 12:14
  • I needed this recently to create class for logging. I wanted to automatically insert the class name + method name when doing a Log() call. Only this solution works. I'd recommend using a for-loop and StackTrace.GetFrame (i) and check each frame's method name (I excluded "log" and "debug", so that it shows me the actual method I want to log). Also use `new StackTrace (2, false);` where 2 is the number of methods within your logger class (you don't want to log anyway) and 'false' is set to halfen performance costs (if you don't need file info). – Battle Oct 11 '21 at 12:38
17

This is actually really simple.

public void PopularMethod()
{
    var currentMethod = System.Reflection.MethodInfo
        .GetCurrentMethod(); // as MethodBase
}

But be careful through, I'm a bit skeptical to if inlining the method has any effect. You can do this to make sure that the JIT compiler won't get in the way.

[System.Runtime.CompilerServices.MethodImpl(
 System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
public void PopularMethod()
{
    var currentMethod = System.Reflection.MethodInfo
        .GetCurrentMethod();
}

To get the calling method:

[System.Runtime.CompilerServices.MethodImpl(
 System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
public void PopularMethod()
{
    // 1 == skip frames, false = no file info
    var callingMethod = new System.Diagnostics.StackTrace(1, false)
         .GetFrame(0).GetMethod();
}
John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • 3
    John Leidgren - That will get me the name "PopularMethod", but I want the name of the method that called PopularMethod. –  Mar 05 '09 at 18:30
  • 1
    Right, well the stack trace is what you need then. I misread your question. – John Leidegren Mar 05 '09 at 18:33
  • The just use .GetFrame(1) instead, right? – Andrew Feb 17 '10 at 23:35
  • 1
    +1 for the `MethodInlining.NoInlining`. BTW the false on the StackTrace .ctor invocation is redundant, isnt it? – Ruben Bartelink Oct 15 '10 at 11:31
  • 1
    I believe it did exhibit slightly better preformance if I didn't ask for the file information explicitly. Truth be told, it probably doesn't matter, the main reason why I did it like that, was because I didn't need the file information. – John Leidegren Oct 15 '10 at 12:08
5

I have often found my self wanting to do this, but have always ending up refactoring the design of my system so I don't get this "Tail wagging the dog" anti-pattern. The result has always been a more robust architecture.

Pieter Germishuys
  • 4,828
  • 1
  • 26
  • 34
JonPen
  • 59
  • 1
  • 1
5

Just pass in a parameter

public void PopularMethod(object sender)
{

}

IMO: If it's good enough for events it should be good enough for this.

twip
  • 638
  • 2
  • 9
  • 20
Sruly
  • 10,200
  • 6
  • 34
  • 39
  • Sruly - Yes that is definitely an option, I was trying to do it without altering the method call. This would be my last resort option. –  Mar 05 '09 at 18:32
  • Unless you are exposing this as a public API, why would you go through a hassle and use reflection if you can just do it this way? REmember KISS – Sruly Mar 05 '09 at 18:38
  • This is the BEST answer, do not use reflection or other stuff, ID the caller via a parameter. – Allen Rice Mar 05 '09 at 18:52
  • If you're looking for something like namespace/assembly info, passing a Type can be a better choice since the call may come from a static method. – Chris Moschini Jan 24 '13 at 01:05
  • 3
    I've written code for many systems. Often developers want to track the method which is writing a log entry. The if the logging code requires manually passing the method name, this requires developer to enter the method name as text every time it calls the logging method. Now use this same logging method in many different parts of the program, and see what happens as methods are added, deleted, and renamed with many developers over a few years. Automating the passing of the caller's method name will greatly ease development and debugging. – Zarepheth Dec 12 '13 at 23:08
1

While you can most definitley trace the Stack and figure it out that way, I would urge you to rethink your design. If your method needs to know about some sort of "state", I would say just create an enum or something, and take that as a Parameter to your PopularMethod(). Something along those lines. Based on what you're posting, tracing the stack would be overkill IMO.

BFree
  • 102,548
  • 21
  • 159
  • 201
0

I think you do need to use the StackTrace class and then StackFrame.GetMethod() on the next frame.

This seems like a strange thing to use Reflection for though. If you are defining PopularMethod, can't go define a parameter or something to pass the information you really want. (Or put in on a base class or something...)

Irshad
  • 3,071
  • 5
  • 30
  • 51
C. Dragon 76
  • 9,882
  • 9
  • 34
  • 41