flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Finding the name of your calling method

Tuesday, February 27, 2007 5:38 PM

One of my absolute favorite things to do is to work on framework components.  I'm not sure why really, I don't think it has anything to do with their importance, I think it's more to do with the way they're used.  They're built by programmers for programmers, there's usually not a UI involved so interaction is handled 'code-to-code', and error conditions are normally communicated via exceptions.  There's just something very cool to me about having to write something that has to be as absolutely rock solid as possible while making it as absolutely flexible as possible since I really won't know in exactly what context it will be used.

So. as geeky as this sounds, I've pretty much been in second heaven lately since I've been refactoring some of our framework components.  The one I've been working on today is logging.  We decided that we needed the current method name reflected in the log statement so we can trace excecution a bit easier.  Yes, this will come at a slight performance impact but we only have logging enabled on production systems for the most extreme levels of errors so we shouldn't have to worry about it too often, and when we do need it we really need it so it's OK.

The easiest way to get the name of your calling method is via reflection using MethodBase, like so...

 MethodBase currentMethod = MethodBase.GetCurrentMethod();

 string caller = currentMethod .DeclaringType.FullName +  '.'  + currentMethod .Name;

This works great...if you're currenlty inside of the method you're interested in.  The obvious problem here when it comes to logging is the GetCurrentMethod() call will actually return our logging routine since that's where it's being called from.  What we need is for the logging routine to know who it was that called it.  The obvious solution here is to simpy pass a reference to the method into the logging routine, similar to how we can verify a calling object.  When I'm building frameworks, however, I like for the API to be as simple as possible to use.  This means that anything that we can figure out for ourselves we don't need the caller to tell us.  We want our API, especially something as utilitarian as logging, to be as simple to use as possible.  If people have to really think about how to use our logging, then they won't use our logging and we won't be able to learn anything when something goes wrong.  It's for this same reason that I'm also a big fan of supplyng your team code snippets for common tasks, we want to make things as absolutely clean and simple for our users as possible.  If we don't then someone else will.

So, ease of use pontifications aside,  what's the easiest way that we can figure out who called us with absolutely as little participation from our users as possible?  Think about you're first computer science class, how do most modern runtimes keep track of where they are?  The stack.  How do we find where something went wrong, when (gasp!) it does?  The stack trace.  Luckily, .NET has functionality built right into the framework to get our current stack trace and move easily to any frame within it...

            // Jump up the stack frame one level and locate the 
            // calling method.
            StackFrame stackFrame = new StackFrame(1);
            MethodBase callingMethod = stackFrame.GetMethod();
 
            // Build a string containing the namespace and method name
            string caller = callingMethod.DeclaringType.FullName +
                '.' + callingMethod.Name;

And that's all there is to it.  We simply create an instance of the StackFrame class telling it how far up the stack we want to look.  In this case, we're looking 1 level up, which means we're looking at the method who called us.  Note that we can go as far up as we need, as long as we don't go deeper than the current stack.  Once we get the StackFrame, we can get the method (every frame has exactly one method) that was in that frame.  Now that we have the method, it's exacty like we called GetCurrentMethod() within it, we can get the namespace (DeclaringType.FullName) and the method name easily.  What's more is that this technique can't be spoofed in the way that the verifying calling objects technique can.

If you've never looked in the System.Diagnostics namespace there are some very cool things in there.  Go ahead, take a look now...I'll wait :)  We can do some pretty advanced things with debugging, programmtically affect our configurations, we can even create an instance of the StackTrace object if we want to work with a whole series of StackFrame objects.  You can do some very cool stuff with this and just a little imagination but keep in mind that we are playing with reflection so you might see a slight performance impact while you're 'imagining'.  That impact, however, shouldn't stop you from simply exploring.

kick it on DotNetKicks.com

Feedback

 re: Finding the name of your calling method

This was very informative - thank you! I'll start using this right away in our global exception-handler routines, to traverse back up the call stack. Nice job explaining this and shining a light on one of the lesser-explored corners of the framework. 2/28/2007 12:40 PM | BigJimSTL

# re: Finding the name of your calling method

Awesome! I'm glad it helped! 2/28/2007 1:52 PM | Jeremy

 re: Finding the name of your calling method

Any way to get the values of paramters on the calling method? 4/2/2007 3:48 PM | Jay

# re: Finding the name of your calling method

Hmm, not that I know of right off hand. I did play around with the StackFrame to pull the ParameterInfo from the method of that object but it looks like we can only retrieve types from that...not values. I'm guessing from the way you worded your comment (specifically asking for 'values') that you have gotten this far already so I won't post the code. However, if you like I can email you my sample code that does this...just drop me a line at Jeremy@JeremyJarrell.com.

I did some poking around on the net and did find two informative threads discussing this same matter. The first thread basically follows the same line of questioning that I tried, the second offers some more solutions. It looks like the only remotely feasible solution is to attach to the debugger API and start pulling the values from there. This idea starts to break down when you move into release (i.e., non-PDB generating) code. I'll keep thinking about it, though and if I come up with anything I'll post a blog entry on it. Be sure to let us know if you come up with anything, too :o)

Here's the links I mentioned..
http://www.thescripts.com/forum/thread231854.html
http://discuss.develop.com/archives/wa.exe?A2=ind0208d&L=advanced-dotnet&D=0&T=0&P=1125

Good luck!

-Jeremy 4/2/2007 4:29 PM | Jeremy

 re: Finding the name of your calling method

Thanks for your information, can i get the line number from this. 4/16/2008 3:52 AM | Ravindran

# re: Finding the name of your calling method

Sure thing, you can use the StackFrame methods GetFileLineNumber(), GetFileName(), and GetFileName() to extract the relevant information. Note that this will only work, however, if the assembly has associated PDB files to work with.

Here's an example...

StackFrame frame = new StackFrame(1);
string fileName = frame.GetFileName();
int lineNumber = frame.GetFileLineNumber();
int columnNumber = frame.GetFileColumnNumber(); 4/16/2008 1:36 PM | Jeremy

Post a comment





 

Please add 1 and 3 and type the answer here: