3

I was wondering if it were possible to obtain the run time type of method callers in the stack trace.

Consider the following example:

class Parent
{
    public void Foo()
    {
        var stack = new StackTrace();

        foreach (var frame in stack.GetFrames())
        {
            var methodInfo = frame.GetMethod();
            Console.WriteLine("{0} (ReflectedType: {1})", methodInfo.ToString(), methodInfo.DeclaringType);
        }
    }
}

class Child : Parent
{
}

If I create an instance of Child and call Foo

var child = new Child();
child.Foo();

Foo will print: Void Foo() (ReflectedType: Parent)

Is there any way to get the actual run time types (Child in this case) of method callers in the stack trace?

Jason Evans
  • 28,906
  • 14
  • 90
  • 154
Patrick M
  • 109
  • 8
  • Very similar: http://stackoverflow.com/questions/23959398/inspect-the-managed-stack – H H Jun 02 '14 at 08:35
  • 1
    Your example is not much useful. You have any other example? In you example for first method `Foo` you can get the original type by `this.GetType()` ? – Sriram Sakthivel Jun 02 '14 at 08:38
  • @SriramSakthivel I was looking for a generic approach that would work for every frame in the stack trace – Patrick M Jun 02 '14 at 08:47

2 Answers2

2

No. The reason is described by Raymond Chen here.

The relevant quote is:

An object in a block of code can become eligible for collection during execution of a function it called.

It's not intuitive, read the part about JIT and GC working together.

Getting the actual Type requires the instance, but the optimization effort is geared toward making that Garbage, so you can't rely on it still being there.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Thanks. The reason I asked is because I'm working with a custom built issue reporting tool that provides a stack trace, however the architecture is really heavy and there are so many method calls from base types it would have been really handy to be able to extend the tool to somehow obtain the run time type. Oh well :) – Patrick M Jun 02 '14 at 08:49
  • 1
    +1 What a fantastic article. Raymond delivers yet again. – Jason Evans Jun 02 '14 at 10:15
0

You are calling Parent.Foo(), that's why you are getting Parent type.

One way would be create a method in Child:

class Parent
{
}

class Child : Parent
{
    public void Foo()
    {
        var stack = new StackTrace();
        foreach (var frame in stack.GetFrames())
        {
            var methodInfo = frame.GetMethod();
            Console.WriteLine("{0} (ReflectedType: {1})", methodInfo.ToString(), methodInfo.DeclaringType);
        }
    }
}

Proof.

But what I can think is the usage. Where do you plan to get that info about stack, types, methods? More likely in some logger. And then you don't really need to know is it Parent.Foo() or Child.Foo(), because you (as programmer) know for sure where Foo() is.

Other thing is what it may be enough (for logger) to only know caller, then it's as simple as

public static void Log(string message, Exception exception = null)
{
    var method = new StackFrame(1).GetMethod();
    // get caller name, so that you don't need to specify it, when calling Log()
    var caller = method.DeclaringType.Name + "." + method.Name;
    ...
}
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • This is trying to roll back the question. But the OPs idea is valid enough. – H H Jun 02 '14 at 12:07
  • Perhaps my example was misleading. I was after a generic solution that would obtain run time types from _any_ frame in the stack trace. Moving methods to child classes doesn't really solve my problem and would compromise OO design in most cases anyway. – Patrick M Jun 02 '14 at 21:53