none
How to get the method signature of instantiated generic type in StackFrame? RRS feed

  • Question

  • Hi folk,

    Say, I have a generic type defined as the following:

        public class GenericClass<TheFirst, TheSecond, TheThird, TheFourth>  
        {  
     
            public void Function1(int scd)  
            {  
                throw new Exception("GenericClass::Function1()");  
            }  
            public void Function2(int scd)  
            {  
                try 
                {  
                    Function1(0);  
                }  
                catch (Exception ex)  
                {  
                    throw new Exception("GenericClass::Function2()", ex);  
                }  
            }  
            public void Function3(TheThird scd)  
            {  
                try 
                {  
                    Function2(0);  
                }  
                catch (Exception ex)  
                {  
                    throw new Exception("GenericClass::Function3()", ex);  
                }  
            }  
        }  
     
        public class Case5  
        {  
            public static void Test()  
            {  
                GenericClass<intintstringstring> temp = new GenericClass<intintstringstring>();  
                temp.Function3("Hello World");  
            }  
        } 

    In catch block, I use StackTrace to fectch the callstack of Exception:
        StackTrace st = new StackTrace(ex);
        StackFrame[] sf = st.GetFrames();
    Or just Exception.StackTrack property:
        ex.StackTrace;

    But as we can see, the methodinfo contained in sf or stacktrace property, is only for the generic type definition one:
        Demo.TestCases.GenericClass`4.Function3(TheThird scd)

    instead of the instantiated one:
        Demo.TestCases.GenericClass`4[[System.Int32, mscorlib],[System.Int32, mscorlib],[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Function3(System.__Canon)
    [From SOS output in windbg]
    How to get the method signature of instantiated generic type in StackFrame?

    Thanks in advance.
    Work For Fun
    Friday, August 1, 2008 5:39 PM

Answers

  • Here is some sample code to get you started:

    using System;
    using System.Diagnostics;
    using System.Reflection;

    namespace ConsoleApplication1 {
        class Program {
            static void Main(string[] args) {
                Case5.Test();
                Console.ReadLine();
            }
        }
        public class GenericClass<TheFirst, TheSecond, TheThird, TheFourth> {

            public void Function1(int scd) {
                throw new Exception("GenericClass::Function1()");
            }
        }

        public class Case5 {
            public static void Test() {
                GenericClass<int, int, string, string> temp = new GenericClass<int, int, string, string>();
                try {
                    temp.Function1(0);
                }
                catch (Exception ex) {
                    StackTrace st = new StackTrace(ex);
                    foreach (StackFrame sf in st.GetFrames()) {
                        MethodBase mb = sf.GetMethod();
                        Console.Write(mb.Name);
                        if (mb is MethodInfo) {
                            MethodInfo mi = mb as MethodInfo;
                            if (mi.ContainsGenericParameters) {
                                Type t = mi.DeclaringType;
                                Type[] args = t.GetGenericArguments();
                                Console.Write("[");
                                for (int ix = 0; ix < args.Length; ++ix) {
                                    Console.Write(args[ix].Name);
                                    if (ix < args.Length - 1) Console.Write(", ");
                                }
                                Console.Write("]");
                            }
                        }
                        Console.WriteLine();
                    }
                }
            }
        }
    }

    Output:
    Function1[TheFirst, TheSecond, TheThird, TheFourth]
    Test

    It is not complete, you'd have to iterate through the DeclaringType chain to find base classes that might be generic.  I didn't bother with it.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, August 7, 2008 2:21 PM
    Friday, August 1, 2008 6:22 PM
    Moderator

All replies

  • Here is some sample code to get you started:

    using System;
    using System.Diagnostics;
    using System.Reflection;

    namespace ConsoleApplication1 {
        class Program {
            static void Main(string[] args) {
                Case5.Test();
                Console.ReadLine();
            }
        }
        public class GenericClass<TheFirst, TheSecond, TheThird, TheFourth> {

            public void Function1(int scd) {
                throw new Exception("GenericClass::Function1()");
            }
        }

        public class Case5 {
            public static void Test() {
                GenericClass<int, int, string, string> temp = new GenericClass<int, int, string, string>();
                try {
                    temp.Function1(0);
                }
                catch (Exception ex) {
                    StackTrace st = new StackTrace(ex);
                    foreach (StackFrame sf in st.GetFrames()) {
                        MethodBase mb = sf.GetMethod();
                        Console.Write(mb.Name);
                        if (mb is MethodInfo) {
                            MethodInfo mi = mb as MethodInfo;
                            if (mi.ContainsGenericParameters) {
                                Type t = mi.DeclaringType;
                                Type[] args = t.GetGenericArguments();
                                Console.Write("[");
                                for (int ix = 0; ix < args.Length; ++ix) {
                                    Console.Write(args[ix].Name);
                                    if (ix < args.Length - 1) Console.Write(", ");
                                }
                                Console.Write("]");
                            }
                        }
                        Console.WriteLine();
                    }
                }
            }
        }
    }

    Output:
    Function1[TheFirst, TheSecond, TheThird, TheFourth]
    Test

    It is not complete, you'd have to iterate through the DeclaringType chain to find base classes that might be generic.  I didn't bother with it.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, August 7, 2008 2:21 PM
    Friday, August 1, 2008 6:22 PM
    Moderator
  • Thank you!! ~~
    I got the result just as you attached. ^^ But the output is not for the constructed type, right? When the generic type is closed (I mean using type argument instead of type parameter, then we can use generic to create an object of it), the correct signature of Function1 should be something like: GenericClass<int, int, string, string>.Function1(int).


    Work For Fun
    Friday, August 1, 2008 6:42 PM
  • Yeah, I fumbled that.  Should have used Console.Write("{0} <", t.Name).  I'm sure you can work it out.
    Hans Passant.
    Friday, August 1, 2008 7:37 PM
    Moderator
  •   Hm~~
    t.Name will return "TheFirst", instead of "int".

    I dumped out the Method Table of both temp and t in the context of above code, and found they are different (as I expected, since constructed type is alive only during runtime):

    EEClass: 008716b4
    Module: 007b2c3c
    Name: Demo.TestCases.GenericClass`4[[System.Int32, mscorlib],[System.Int32, mscorlib],[System.__Canon, mscorlib],[System.__Canon, mscorlib]]
    mdToken: 02000002 
    BaseSize: 0xc
    ComponentSize: 0x0
    Number of IFaces in IFaceMap: 0
    Slots in VTable: 8

    EEClass: 00871650
    Module: 007b2c3c
    Name: Demo.TestCases.GenericClass`4
    mdToken: 02000002 
    BaseSize: 0xc
    ComponentSize: 0x0
    Number of IFaces in IFaceMap: 0
    Slots in VTable: 8

    Seems like StackTrace cannot get the real type info when resolving generic type/method during the stack walk. It only uses type definition.


    Work For Fun
    Friday, August 1, 2008 8:03 PM