Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get real type of generic method from StackFrame

Tags:

c#

reflection

In my logging module I have the line:

MethodBase methodBase = new StackFrame(2, false).GetMethod();

The method I inspect is a generic method and defined as T[] MyMethod<T>(). Is there a way to get its real type instead of T from methodBase?

like image 749
Denis Avatar asked Jan 02 '15 00:01

Denis


1 Answers

As far as I know, you can't do this. The information in the StackFrame is retrieved not from run-time information, but from the .pdb information, correlating the return address found in the stack frame with the assembly offsets described in the .pdb. I.e. only the compile-time information is available, which of course is the open generic method.

Note that even if you manually construct a closed generic method and invoke it directly, you still get the open generic method from the .pdb. For example:

class Program
{
    static void Main(string[] args)
    {
        MethodInfo miOpen = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.NonPublic),
            miClosed = miOpen.MakeGenericMethod(typeof(int));

        Type type;

        object[] invokeArgs = { 17, null };
        int[] rgi = (int[])miClosed.Invoke(null, invokeArgs);

        type = (Type)invokeArgs[1];
    }

    static T[] Method<T>(T t, out Type type)
    {
        type = GetMethodType();

        return new[] { t };
    }

    private static Type GetMethodType()
    {
        StackFrame frame = new StackFrame(1, false);
        MethodBase mi = frame.GetMethod();

        return mi.GetGenericArguments()[0];
    }
}

In the above example, the type variable value assigned at the end still references the {T} type for the open generic method, not Int32 as you would hope in your case. This, in spite of the fact that the Int32 type is retrievable from the miClosed variable reference.

If you want the specific type information, you will have to provide a mechanism in your code to determine it explicitly (e.g. pass the value of typeof(T) to the logging component from the generic method itself). The StackFrame class doesn't have the necessary information to do that for you.

like image 85
Peter Duniho Avatar answered Oct 24 '22 09:10

Peter Duniho