Sign in to follow this  
Dope-Show

[.net] Find out method's caller

Recommended Posts

Is it possible to find out a method's caller at runtime, or does any other way exist, which allows to examine the call stack at runtime? Since this thread is posted in the .NET section, suppose it is about .NET ;-)

Share this post


Link to post
Share on other sites
System.Diagnostics.StackTrace is your friend.
However this does not work reliably of course due to the JIT performing inlining and other operations. ( you will get methods not showing up in the stacktrace that have been inlined but still exist in your source code )

Share this post


Link to post
Share on other sites
Thanks for your help.
After trying out and looking into the documentation i found out, that it only works correctly with debug builds (well, of course it works correctly with release builds, too, but it does not work the way i expected ;-))
Thanks again, but i need to find another way.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gluber
However this does not work reliably of course due to the JIT performing inlining and other operations. ( you will get methods not showing up in the stacktrace that have been inlined but still exist in your source code )

These limitations apply to any method you'd use that are built into the .NET Framework, though. It's good to be aware of the limitations, yes, but it should be noted that those limitations are part of the Framework and not the language or the StackTrace() class. (You could also disable optimizations, although this isn't something I could imagine being that important.)

Sample code for the curious:
StackTrace st = new StackTrace();
StackFrame sf = st.GetFrame(0);
Console.WriteLine("{0}", sf.GetMethod());
You might find the System.Reflection namespace useful. You can get the name of the currently executing method using the MethodInfo.GetCurrentMethod() static function.
MethodInfo mi = (MethodInfo) MethodInfo.GetCurrentMethod();
Console.WriteLine("{0}", mi.Name);
If you execute the above inside a constructor you'll have to use ConstructorInfo in place of MethodInfo.

Using the above method you could set a static member to the currently executing method, accessed by whichever component you want. (If you're threading you'll need to create a static array, of course.) However, that system causes a runtime performance penalty whereas the StackTrace method only causes a penalty when it is needed or invoked.

I've used the StackTrace method as part of a logging class and never had an issue with it. Generally if a method is going to be inlined or optimized to the point of losing its identity that method isn't large enough to be the cause of a lot of problems. Even if it would be I don't think it'd be difficult to find.

Share this post


Link to post
Share on other sites
My problem is not the limitation of the framework, but the missing debug symbols

The following source


class Program
{
static void X()
{
Y();
}

static void Y()
{
Z();
}

static void Z()
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();

Console.WriteLine(st);
}

static void Main(string[] args)
{
X();
}
}



results in the following output with debug build:

at test.Program.Z()
at test.Program.Y()
at test.Program.X()
at test.Program.Main(String[] args)
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

while the release build results in:

at test.Program.Z()
at test.Program.Main(String[] args)


missing the X and Y static methods

Share this post


Link to post
Share on other sites
Quote:
Original post by Talonius
You might find the System.Reflection namespace useful. You can get the name of the currently executing method using the MethodInfo.GetCurrentMethod() static function.
MethodInfo mi = (MethodInfo) MethodInfo.GetCurrentMethod();
Console.WriteLine("{0}", mi.Name);
If you execute the above inside a constructor you'll have to use ConstructorInfo in place of MethodInfo.

No, you don't. ConstructorInfo and MethodInfo both inherit from MethodBase, which inherits from MemberInfo. MemberInfo is the class that contains the Name property, MethodBase is the class that contains the GetCurrentMethod() function.

MethodBase currentMethod = MethodBase.GetCurrentMethod();
Console.WriteLine("{0}", currentMethod.Name);

Quote:
Original post by Dope-Show
missing the X and Y static methods

As to be expected, since your static methods don't DO anything at all except delegate to the next static method.

Share this post


Link to post
Share on other sites
Oh, right, they are optimized away by the compiler i suppose.
But after adding Console.WriteLine("test"), they still didn't show up in the StackTrace.
Adding for(int i = 0; i < 10; i++) makes them show up.

So now the Question is, what operations does the compiler optimize away, and which don't.

Share this post


Link to post
Share on other sites
Quote:
Original post by Washu
No, you don't. ConstructorInfo and MethodInfo both inherit from MethodBase, which inherits from MemberInfo. MemberInfo is the class that contains the Name property, MethodBase is the class that contains the GetCurrentMethod() function.
Meh, I prefer to work at the most defined level, sorry. :)
Quote:
Original post by Dope-Show
So now the Question is, what operations does the compiler optimize away, and which don't.
My understanding is that the compiler doesn't do most of the optimizations, the JITter handles most of that. Constants are inlined, some methods may be unrolled, etc. Some of the optimizations are discussed in this MSDN article.

I don't think you can ever count on being able to know what optimizations might be done. There are multiple host Frameworks around now, each a little different than the other.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bob Janova
I don't know, but anything not involving any declaration of local variables would be a good bet, since that doesn't need the function's scope to work.


I tested it, but no difference

Quote:
Original post by Talonius
My understanding is that the compiler doesn't do most of the optimizations, the JITter handles most of that.


Well, the JITter is also a compiler, a Just-In-Time Compiler, but that doesn't matter, does it? [wink]

So is there a way to find out a method's caller, that actually works and is reliable?

[Edited by - Dope-Show on March 17, 2006 2:02:28 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Dope-Show
Well, the JITter is also a compiler, a Just-In-Time Compiler, but that doesn't matter, does it? [wink]

So is there a way to find out a method's caller, that actually works and is reliable?


Heh heh. Semantics!

The only way I can think of is to manually track the function name yourself ala the static variable. Everything else is subject to the whim of the system.

Washu might have some more ideas. He is DotNetGod! :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Talonius
Quote:
Original post by Washu
No, you don't. ConstructorInfo and MethodInfo both inherit from MethodBase, which inherits from MemberInfo. MemberInfo is the class that contains the Name property, MethodBase is the class that contains the GetCurrentMethod() function.
Meh, I prefer to work at the most defined level, sorry. :)

That's silly. The more abstract the level you work on, the less you have to worry about implementation details. The less you have to worry about implementation details the faster your ability to test, develop and debug code.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this