Skip to content

Faster MethodInfo.Invoke #7560

Closed
Closed
@davidfowl

Description

@davidfowl

When writing a framework that dispatches to user methods it's quite common to reflect over all methods of a particular shape on an object and store a MethodInfo for later use. The scan and store is typically a one time cost (done up front) but the invocation of these methods happen lots of times (one or many times per http request for example). Historically, to make invocation fast, you would generate a DynamicMethod using reflection emit or generate a compiled expression tree to invoke the method instead of using methodInfo.Invoke. ASP.NET does this all the time, so much so that we now have a shared component to do this (as some of the code can be a bit tricky).

With the advent of newer runtimes like project N and coreRT, it would be great if there was first class support for creating a thunk to method. This is what I think it could look like:

class Program
{
    // First class delegate type in the CLR use to express the stub that calls into the
    // underlying method
    public delegate object Thunk(object target, object[] arguments);

    static void Main(string[] args)
    {
        var methods = typeof(Controller).GetMethods();
        var map = new Dictionary<string, Thunk>();
        foreach (var methodInfo in methods)
        {
            map[methodInfo.Name] = methodInfo.CreateThunk();
        }

        // Invoke the method index (result is null)
        var result = Invoke(map, typeof(Controller), "Index");

        // Result is 3 (yes things get boxed)
        result = Invoke(map, typeof(Controller), "Add", 1, 2);
    }

    private static object Invoke(Dictionary<string, Thunk> map, Type type, string method, params object[] arguments)
    {
        var target = Activator.CreateInstance(type);
        return map[method](target, arguments);
    }
}

public class Controller
{
    public void Index()
    {

    }

    public int Add(int a, int b)
    {
        return a + b;
    }
}

Few notes:

  • We could disable type checking in the stub, if the caller passes the wrong arguments they would get an invalid cast exception.
  • The arguments and return values are always boxed (that's not a huge deal for our use cases at least).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.ReflectionenhancementProduct code improvement that does NOT require public API changes/additionstenet-performancePerformance related issueuntriagedNew issue has not been triaged by the area owner

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions