28

What I'm wondering is if it's possible to (for instance) to walk up the stack frames, checking each calling object to see if matches an interface, and if so extract some data from it.

Yes, I know it's bad practice, I'm wondering if it's possible.

Bill Tarbell
  • 4,933
  • 2
  • 32
  • 52
Andrew Ducker
  • 5,308
  • 9
  • 37
  • 48

3 Answers3

27

No, there isn't - at least not without using a profiling/debugging API of some description. You can walk the stack to find the calling method, with the caveat that it's really slow and may be inaccurate due to JIT optimisations. That won't tell you what the calling object is though (if indeed there is one).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Aaaah - so presumably VS does it in some kind of complicated way by instrumenting the code? – Andrew Ducker Jan 07 '09 at 14:57
  • Well, not by instrumenting the code so much as running the debugger APIs which give all kinds of information - at a price, of course. – Jon Skeet Jan 07 '09 at 15:07
  • 2
    Oooh - where can I find moer info on these debugger APIs? – Andrew Ducker Jan 07 '09 at 16:29
  • andrewducker: To be honest, I'd just be doing Google searches to find out, so I'll let you do those instead :) I've never used the debugger/profiler APIs - given the low-level stuff they're for, I expect they may be a pain to use. – Jon Skeet Jan 07 '09 at 17:08
  • 2
    So this nailed me with some logging code that was trying to be too clever, examining the StackTrace and going up frames to get the name of the calling method. You can do that by simple counting in Debug mode, but in Release mode, well, some methods get optimized away. A great tip! – Nicholas Piasecki Mar 23 '09 at 20:36
7

If you want to get the type you can try this:

new StackFrame(1).GetMethod().DeclaringType

As Jon pointed out there might be issues if you run into JIT optimizations.

As for getting data from the object, I don't think it's possible.

Edit

Just to elaborate on the optimization issue, take the following code:

class stackTest
{
    public void Test()
    {
        StackFrame sFrame = new StackFrame(1);
        if (sFrame == null)
        {
            Console.WriteLine("sFrame is null");
            return;
        }

        var method = sFrame.GetMethod();

        if (method == null)
        {
            Console.WriteLine("method is null");
            return;
        }
        Type declaringType = method.DeclaringType;
        Console.WriteLine(declaringType.Name);
    }

    public void Test2()
    {
        Console.WriteLine(new StackFrame(1).GetMethod().DeclaringType.Name);
    }
}

class Program
{
    static void Main(string[] args)
    {

        stackTest s = new stackTest();
        s.Test();
        Console.WriteLine("Doing Test2");
        s.Test2();
        Console.ReadLine();

    }
}

We should get Program to the console twice, and when you run within the debugger you do. When you run without the debugger in release mode, you get the output from the first Test function. Which is probably because it is to complex to be inlined, however, the second method causes a null reference exception.

Another danger with this code is that at MS improves the JIT compiler what might have worked in 2.0 could crash and burn in future versions.

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
JoshBerke
  • 66,142
  • 25
  • 126
  • 164
  • The inlining can be avoided with `[MethodImpl(MethodImplOptions.NoInlining)]` – Fabio Iotti Oct 12 '22 at 14:13
  • Nevermind, `MethodImplOptions.NoInlining` is not sufficient, as it would only prevent the called method to be inlined, but not the calling method. https://sharplab.io/#v2:C4LghgzgtgPgAgBgARwIwDoBKBXAdsASygFN0BhAeygAcCAbYgJwGUmA3AgY2IgG4BYAFBC2YRkgAeSALxJcxAO5IAGgAoAlAMET0AIQ1ahcAMwoATCqQBvIUjspTBfEn3rrt+57IGPnu3AB2JFQtTwBfIV8kAG0AWWJgAAsKABMASRo6VXik1IzqOgB5akIKXAh0ADkKNNw6JycAc3UAXSiTFFQANhQAFiRvNxtBcKEI4UEgA== – Fabio Iotti Oct 12 '22 at 14:37
0

See this question:
Can you use reflection to find the name of the currently executing method?

It's not a duplicate, but the answer to that question will answer yours as well.

Community
  • 1
  • 1
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    Not really - because while it's feasible to get the calling method, that doesn't tell you the actual type of the object making the call. For instance, it could be in BaseClass.Foo() but from an instance of DerivedClass which implements an interface that Andrew is looking for. – Jon Skeet Jan 07 '09 at 14:51
  • It does give you a stack trace, though. – Joel Coehoorn Jan 07 '09 at 14:53