Search code examples
c#reflectionsystem.reflection

Get calling method using StackTrace


I have two scenarios where I want to know which is the caller method of some method I´m executing.

These are the scenarios:

1)

public static void ExecuteMethod(object obj)
{
    var mth = new StackTrace().GetFrame(1).GetMethod();
    string methodName = mth.Name;
}

And I call it this way:

public class Process
{
    public int Handle { get; set; }
    public string Name { get; set; }
    public int ProcessID { get; set; }

    public dynamic GetOwner()
    {
        return WMIMethod.ExecuteMethod(this);
    }
}

When this is executed the result of methodName is the one I expect: GetOwner

The second and problematic scenario is this one:

2)

public static dynamic ExecuteMethod(object obj, dynamic parameters)
{
    var mth = new StackTrace().GetFrame(1).GetMethod();
    string methodName = mth.Name;
}

And I call it this way:

public class Process
{
    public int Handle { get; set; }
    public string Name { get; set; }
    public int ProcessID { get; set; }

    public dynamic GetOwner(dynamic inParams)
    {
        return WMIMethod.ExecuteMethod(this, inParams);
    }
}

In this scenario, when I call new Process().GetOwner(new { MyParam = "Something" } ) the result of methodName isn´t anymore what I would expect to be (GetOwner) and instead of that methodName is CallSite.Target and the result of mth is

{Void CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Type, ORMi.Sample.Models.Printer, System.Object)}

Anyone knows why is the second case different of the first one??. How can this be solved???.

Thanks!.


Solution

  • From what I've found is that when dynamic object is used, C# adds an additional method call System.Dynamic.UpdateDelegates.UpdateAndExecute3().

    In your case I'd rewrite the second method as

    public static dynamic ExecuteMethod(object obj, dynamic p)
    {
        var frame =
            new StackTrace().GetFrames()
                            .Skip(1) // Skip the 'ExecuteMethod'
                            .First(x => x.GetMethod().DeclaringType.Namespace != "System.Dynamic");
    
        return frame.GetMethod().Name;
    }
    

    Unfortunately, I have no idea why C# inserts that call, so I'll appreciate if someone can explain that internal work.