Click here to Skip to main content
15,889,200 members
Articles / Programming Languages / C#
Article

A General Fast Method Invoker

Rate me:
Please Sign up or sign in to vote.
4.96/5 (76 votes)
4 Jul 20061 min read 265.8K   3.1K   178   74
Method reflecting invoke is nice, but very frequently it can be too slow. This article describes an alternative method for dynamic method invoke.

Sample Image - FastMethodInvoker.gif

Introduction

Sometimes, I run across the need to dynamically invoke the method of an object, where the actual method might not be known until run-time. Usually, Reflecting is nice, but frequently doing it can be too slow. This article describes an alternative method for dynamic method invocation.

Background

When I read the article Fast Dynamic Property Accessors, I was thinking about my project, it has a lots of reflecting methods in circle. But it's methods not properties. But the DynamicMethod reminded me, maybe I could use Emit to generate a DynamicMethod to bind a special method before it can be invoked. I hope it will improve performance.

Using the Code

First, I reflected out the method which will be invoked:

C#
MethodInfo methodInfo = typeof(Person).GetMethod("Say");

Then, I get the MethodInvoker to invoke:

C#
FastInvokeHandler fastInvoker = GetMethodInvoker(methodInfo);
fastInvoker(new Person(), new object[]{"hello"});

Instead of using reflection method, invoke in the past:

C#
methodInfo.Invoke(new Person(), new object[]{"hello"});

Implementation

First, I need to define a delegate to adapt the dynamic method:

C#
public delegate object FastInvokeHandler(object target, 
                                   object[] paramters);

It looks the same as the class MethodInfo's Invoke method. Yes, that means I can write the same code to use it like in the past.

This code generates the DynamicMethod:

C#
public static FastInvokeHandler GetMethodInvoker(MethodInfo methodInfo)
{
    DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, 
                     typeof(object), new Type[] { typeof(object), 
                     typeof(object[]) }, 
                     methodInfo.DeclaringType.Module);
    ILGenerator il = dynamicMethod.GetILGenerator();
    ParameterInfo[] ps = methodInfo.GetParameters();
    Type[] paramTypes = new Type[ps.Length];
    for (int i = 0; i < paramTypes.Length; i++)
    {
        paramTypes[i] = ps[i].ParameterType;
    }
    LocalBuilder[] locals = new LocalBuilder[paramTypes.Length];
    for (int i = 0; i < paramTypes.Length; i++)
    {
        locals[i] = il.DeclareLocal(paramTypes[i]);
    }
    for (int i = 0; i < paramTypes.Length; i++)
    {
        il.Emit(OpCodes.Ldarg_1);
        EmitFastInt(il, i);
        il.Emit(OpCodes.Ldelem_Ref);
        EmitCastToReference(il, paramTypes[i]);
        il.Emit(OpCodes.Stloc, locals[i]);
    }
    il.Emit(OpCodes.Ldarg_0);
    for (int i = 0; i < paramTypes.Length; i++)
    {
        il.Emit(OpCodes.Ldloc, locals[i]);
    }
    il.EmitCall(OpCodes.Call, methodInfo, null);
    if (methodInfo.ReturnType == typeof(void))
        il.Emit(OpCodes.Ldnull);
    else
        EmitBoxIfNeeded(il, methodInfo.ReturnType);
    il.Emit(OpCodes.Ret);
    FastInvokeHandler invoder = 
      (FastInvokeHandler)dynamicMethod.CreateDelegate(
      typeof(FastInvokeHandler));
    return invoder;
}

Conclusion

Well, I think this is a general way that can be used instead of most of the reflection methods to get about 50 times performance improvement. Any suggestions for improvements are welcome.

Extra advantage (reminded by MaxGuernsey): If an exception occurs in your code, FastInovker would throw the original one, but the Method.Invoke would throw a TargetInvocationException.

History

  • 2006-7-05: Updated to add static method support. Thanks Manuel Abadia.
  • 2006-6-30: Updated to add ref/out parameter support. Thanks Roger for his nice suggestion.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
China China
I am currently working for a .NET framework names AgileFramework. It's introduction at here:
http://www.agilelabs.cn/agileframework

Now I'm living in China. I have been designing and developing .NET based software applications for 5+ years.

Comments and Discussions

 
JokeJust great Pin
Alexander German30-Jun-06 13:53
Alexander German30-Jun-06 13:53 
GeneralGreat, Great, Great !!! Pin
Marcos Meli30-Jun-06 10:16
Marcos Meli30-Jun-06 10:16 
GeneralA good article... Pin
Jun Du30-Jun-06 9:20
Jun Du30-Jun-06 9:20 
GeneralRe: A good article... Pin
Luyan3-Jul-06 22:58
Luyan3-Jul-06 22:58 
GeneralKudos + Suggestion Pin
Josh Smith30-Jun-06 8:39
Josh Smith30-Jun-06 8:39 
GeneralRe: Kudos + Suggestion Pin
Luyan3-Jul-06 22:53
Luyan3-Jul-06 22:53 
GeneralRe: Kudos + Suggestion Pin
Drew Noakes4-Jul-06 4:49
Drew Noakes4-Jul-06 4:49 
GeneralRef and out params [modified] Pin
Roger Alsing29-Jun-06 17:40
Roger Alsing29-Jun-06 17:40 
It doesnt work with ref and out params, it generates invalid non executable IL code for those.

either way, this is really good.
Im goona use this in NAspect to optimize the interception flow Smile | :)

Im almost done now, its only my ref/out params unit test that fail.
Any idea how to fix that?

also, dont know if there is a good way to see if a param is a ref/out param , I had to check if the type name ends with "&".

So when you are storing the values from the passed object[]
you need to make your locals use the real type , eg "int" instead of "int&"
and you have to load the ref before you store the value in the locals.

and when you push the locals to the stack before the call you need to load those locals as refs

and after the call has returned , you need to somehow copy the ref data back to the object[].
so that the invoker can see the changes.


//Roger

http://www.puzzleframework.com

-- modified at 1:07 Friday 30th June, 2006
GeneralRe: Ref and out params Pin
Luyan30-Jun-06 0:06
Luyan30-Jun-06 0:06 
GeneralRe: Ref and out params Pin
Roger Alsing30-Jun-06 2:06
Roger Alsing30-Jun-06 2:06 
GeneralRe: Ref and out params Pin
Luyan30-Jun-06 3:05
Luyan30-Jun-06 3:05 
GeneralRe: Ref and out params [modified] Pin
Roger Alsing30-Jun-06 3:26
Roger Alsing30-Jun-06 3:26 
GeneralRe: Ref and out params Pin
Luyan30-Jun-06 3:35
Luyan30-Jun-06 3:35 
GeneralRe: Ref and out params Pin
Roger Alsing30-Jun-06 9:40
Roger Alsing30-Jun-06 9:40 
General5 from me Pin
M Harris29-Jun-06 15:22
M Harris29-Jun-06 15:22 
GeneralRe: 5 from me Pin
Luyan30-Jun-06 0:20
Luyan30-Jun-06 0:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.