views:

3159

answers:

8

When logging in C#, how can I learn the name of the method that called the current method? I know all about System.Reflection.MethodBase.GetCurrentMethod(), but I want to go one step beneath this in the stack trace. I've considered parsing the stack trace, but I am hoping to find a cleaner more explicit way, something like Assembly.GetCallingAssembly() but for methods.

+25  A: 

How about...

using System.Diagnostics;
// get call stack
StackTrace stackTrace = new StackTrace();

// get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

From here?

Firas Assaad
That deffo works because thats the solution we used at work...not sure why we did it though!
pzycoman
You can also create just the frame you need, rather than the entire stack:
Joel Coehoorn
new StackFrame(1).GetMethod().Name;
Joel Coehoorn
This isn't entirely reliable though. Let's see if this works in a comment! Try the following in a console application and you see that compiler optimsations break it.static void Main(string[] args){ CallIt();}private static void CallIt(){ Final();}static void Final(){ StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); Console.WriteLine("{0}.{1}()", frame.GetMethod().DeclaringType.FullName, frame.GetMethod().Name);}
BlackWasp
Ah well, thought the comments may not like it.
BlackWasp
+3  A: 

Note that doing so will be unreliable in release code, due to optimization. Additionally, running the app in sandbox mode (network share) won't allow you to grab the stack frame at all.

Have you considered AOP, like PostSharp, which instead of being called from your code, modifies your code, and thus knows where it is at all times?

Lasse V. Karlsen
A: 

Take a look at: http://www.codeproject.com/KB/dotnet/MethodName.aspx

Beware of using it in production code. StackFrame may not be reliable...

Yuval Peled
+12  A: 

NOTE: Just expanding on the answer provided by Firas Assad

In general, you can use the System.Diagnostics.StackTrace class to get a System.Diagnostics.StackFrame, and then use the GetMethod() method to get a System.Reflection.MethodBase object. However, there are some caveats to this approach:

  1. It represents the runtime stack -- optimizations could inline a method, and you will _**not**_ see that method in the stack trace.
  2. It will _**not**_ show any native frames, so if there's even a chance your method is being called by a native method, this will _**not**_ work, and there is in-fact no currently available way to do it.
Alex Lyman
+11  A: 

We can improve on Mr Assad's code (the current accepted answer) just a little bit by instantiating only the frame we actually need rather than the entire stack:

new StackFrame(1).GetMethod().Name;

This should perform a little better. However, it still has the same caveats that Alex Lyman pointed out. Also, you might want to check to be sure that new StackFrame(1) or .GetFrame(1) don't return null, as unlikely as that possibility might seem.

See this related question: http://stackoverflow.com/questions/44153/can-you-use-reflection-to-find-the-name-of-the-currently-executing-method

Joel Coehoorn
A: 

Maybe you are looking for something like 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
jesal
A: 

Another approach I have used is to add a parameter to the method in question. For example, instead of void Foo(), use void Foo(string context). Then pass in some unique string that indicates the calling context.

If you only need the caller/context for development, you can remove the param before shipping.

GregUzelac
A: 
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}
Flanders
oops, I should have explained the "MethodAfter" param a little better. So if you are calling this method in a "log" type function, you'll want to get the method just after the "log" function. so you would call GetCallingMethod("log").-Cheers
Flanders