Invoking methods dynamically in C#: Examples and benchmarks

Introduction

Imagine that you have a service, which receives requests to execute specific methods, possibly from a number of different underlying libraries that you don’t want to expose directly. Possible examples are web services. The request comes in as a number of string values (method name, parameters etc.) and you need to respond with results.

So you have inherited a project with API that starts with a method:


object Invoke(string methodName, object[] parameters);

You now have to call variety of methods by decoding the name of the method and parameters provided into the method. In my precise case the signatures were a bit different and more complicated, but for the sake of simplicity let’s keep it that easy.

Let’s assume now you have two methods that you want to call using this API:


public static string TestString1(string a)
{
    return "Received: " + a;
}

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

You get the point: different method names, different number of arguments of different types and names.

Problem

How to dynamically invoke appropriate method with supplied arguments the most efficient way? How to not hard-code the method names and arguments in a series of if-else statements that would grow and get unreadable very quickly?

Possible approaches

There are couple of approaches I will discuss here. All are assuming that you already got the type of the class that defines the target method. This could be achieved on many ways and in order to make this post a bit shorter and easier to read, I will skip it. If you find it useful to blog about it, let me know in the comments.

MethodInfo.Invoke

One of the first things that you will likely find on the web is the MethodInfo.Invoke method from System.Reflection namespace.

The usage is very easy:


//get the method from a given type definition
MethodInfo method = typeof(Program).GetMethod("TestString1");

//build the parameters array
object[] _stringMethodParams = new object[] { "lalamido" };

//invoke the method
object result = method.Invoke(null, _stringMethodParams);

The first parameter of Invoke method, defines the instance of the object we want to execute the method against, but since our methods are static, we don’t need any instance, hence null value. As you could see it’s relatively easy to use. The only thing that’s wrong with this approach is performance,  but I think the best way to get the impact is to see comparison,  so we’ll get back to this later in this post.

Delegate.DynamicInvoke

Another approach you can find on the Internet is DynamicInvoke of Delegate class. The usage looks like that:


MethodInfo info1 = typeof(PublicReadMethods).GetMethod("TestString");
Delegate _mi1 = Delegate.CreateDelegate(
    Expression.GetDelegateType(
         (from parameter in info.GetParameters() 
          select parameter.ParameterType)
         .Concat(new[] { info.ReturnType })
         .ToArray()), info);

_stringMethodParams = new object[] { "lalamido" };

_mi1.DynamicInvoke(_stringMethodParams);

I think that the code is also quite easy, except (maybe) the delegate creation which expects a type of delegate. Here we have used LINQ Expressions to build it. The method Expression.GetDelegateType accepts an array of types and builds the delegate type out of it. The last type provided in array defines the returned value type.

Expression trees

Since we already used Expression class in our previous example, we could go one step further. Expression trees are how the Expressions are represented in memory as an object. Following MSDN:

The System.Linq.Expressions namespace contains classes, interfaces and enumerations that enable language-level code expressions to be represented as objects in the form of expression trees.

What does it actually bring into the discussion?

Our c# code is built using expressions and other syntactical constructs like  for example, clauses, or statements.

After you write code in your favorite IDE, you need to compile and JIT (of course, speaking about .NET platform only here). Now the easy thing about it is that at compile time, compiler knows the signature of your methods and the types of the arguments, so you can perform some direct calls in your code and compiler is happy.

But what if you don’t know it at that moment? Well, the compiler needs to be happy, so usually people go through reflection, which doesn’t assume much at the compile time, so it may result in exceptions at runtime. Another thing is that reflection is slow, because it involves a lot of type-checking and matching at runtime, where we would like the code simply to perform well.

Expression Trees are a way to make both worlds happy. You can write a c# code, that is able to represent code expressions as objects. Then, at runtime, you can compile the expression and use it almost as if you would be using direct invokation. Just for the sake of completeness I will mention two ways to call the methods when the type is known at compile-time, because except the compilation phase, the execution time for Expression Trees ads small-or-no overhead.

So how do we represent our methods as Expression Trees? Let’s try to analyze it in the opposite direction, so starting from the method invokation:

public delegate object LateBoundMethod(object target, object[] arguments);
LateBoundMethod _mi1 = DelegateFactory.Create(typeof(PublicReadMethods).GetMethod("TestString"));
_mi1.Invoke(null, _stringMethodParams);

Looking at this example, and the MethodInfo one that we’ve started with, it looks quite similar. The details are hidden in the Create method of DelegateFactory class. It returns a delegate, which has accepts the target object and array of objects as arguments, and returns object-type result.

The DelegateFactory class implementation is based on Nate Kohari‘s blog post which is not available today for reading (returns 404), but I will explain the implementation a little bit more. You can check the full source code >here<.

Let’s examine it a step further. We have defined a delegate, which (surprisingly :)) accepts a target object and array of arguments and returns an object. Now we need to construct such a delegate. Late bound methods are generally speaking bound to its types at runtime, contrary to early binding which occurs at compile time.

So we called Create method, which accepts MethodInfo argument, here’s the code:

ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "target");
ParameterExpression argumentsParameter = Expression.Parameter(typeof(object[]), "arguments");

MethodCallExpression call = Expression.Call(method,
    CreateParameterExpressions(method, argumentsParameter));

Expression<LateBoundMethod> lambda = Expression.Lambda<LateBoundMethod>(
    Expression.Convert(call, typeof(object)),
    instanceParameter,
    argumentsParameter);

return lambda.Compile();

First thing we have to do is we have to construct our two parameters, which will be represented as Expressions. We do this by calling Expression.Parameter with two arguments: type and name of the parameter.

Then we have to get our method call expression, there’s also a Type for that, which name is self-explanatory: MethodCallExpression. We get it via Expression.Call method, which accepts MethodInfo object and an array of Expressions that will be used as arguments collection. So far so good. Now we have to build the array of arguments Expressions. We use another method for that:

private static Expression[] CreateParameterExpressions(MethodInfo method, Expression argumentsParameter)
{
    return method.GetParameters().Select((parameter, index) =>
        Expression.Convert(
            Expression.ArrayIndex(argumentsParameter, Expression.Constant(index)),
            parameter.ParameterType)).ToArray();
}

The method GetParameters returns an array of ParameterInfo objects from System.Reflection Namespace.

Then, using LINQ, we’re enumerating through the parameters we’ve got from the GetParameters method and appropriately converting our parameters Expression (that we have declared at the beginning of Create method) to the expression with the given type.

Next we need to build Expression that will represent our LateBoundMethod delegate. There’s a method for that as well, we need to provide the Expression body for the lambda and the expression arguments that must be corresponding to the class we provided as TDelelegate generic type. Obviously this type also has to be a Delegate.

Expression<LateBoundMethod> lambda = Expression.Lambda<LateBoundMethod>(
    Expression.Convert(call, typeof(object)),
        instanceParameter,
        argumentsParameter);

Last, but not least, once we have built our expression that represents our lambda (Delegate),  we need to compile,  before using it. Once the expression is compiled,  we get a Delegate that is ready to be invoked.

return lambda.Compile();

It might look a bit hard at the beginning, but I advise you to read a bit more about Expression Trees as that is generally speaking a very nice feature of .NET that you shouldn’t miss. I can recommend Chapter 11 (Inside Expression Trees) and chapter 12 (Extending Linq) of Programming Microsoft Linq book.

How does it perform? Well,  apparently it does quite well. The overhead that we can’t ignore is added by the compilation. Which is quite reasonable. Every C# code we’re using needs to be compiled. The only difference is that if you compile it in your IDE, you don’t even bother about it as it doesn’t impact your application’s performance.

In order to visualize the impact, I have split the code execution into two parts.  This way we can see how long does it take to prepare the execution and how long does the execution really take. We’ll get back to this point after presenting tests results.

Compile time typed methods

Just to make this comparison more valuable, I will also compare times for calling those methods using early binding. Of course first way to call a method you know everything about at compile time is to actually directly call it. Like that 🙂

Program.TestString("lalamido");

Another way is to have Delegate with types defined.

 
static Func<string,string> _testString;
_testString = Program.TestString;
_testString.Invoke("lalamido");

Those two ways I think don’t need any explanation and represent most probably the 99% your standard way of invoking methods. Since everything is known at compile time, we also expect those two to be the quickest ones. Let’s see how it goes.

Benchmarks

Setup

In the setup part, we are preparing everything for execution. This includes getting the MethodInfo object, or compiling the ExpressionTree so that in the Execution phase we can only focus on the execution time.

Execution

The execution part is executing the two methods that I mentioned on the beginning, in a for loop with a parametrized iterations number.

Results

Setup was executed only once for each approach. The objects were then used iteratively in tests.

Dynamic Invokation Setup

As you can see, proportionally Expression Trees have been the longest to prepare, head-to-head with DynamicInvoke. That doesn’t look good.

On a second thought, this may be (probably) done only once and then reused, so using some kind of memory container, cache or something, you could pre-calculate things before they are really used and benefit from the execution times later on. This may also not be the case, so one has to be careful when using each of those in different scenarios.

Execution test have been run with 1000, 10 000, 100 000 and 1 000 000 iterations. The average results are as follows.

1 000 iterations

Dynamic Invokation 1000 runs

10 000 iterations

Dynamic Invokation 10 000 runs

100 000 iterations

Dynamic Invokation 100 000 runs

1 000 000 iterations

Dynamic Invokation 1 000 000 runs

Conclusions

The results for the first tests may have looked surprisingly. Direct invokation slower than expression tree invokation? Even delegate was faster. Maybe we should use delegates all the time, instead of directly invoking the methods.

Later, we could see that the results have been normalized and finally the results are quite clear.

Methods of invokation that types we know at compile time are the fastest ones.

Expression Trees are last on the podium, but I think all will agree that result is awesome, comparing to MethodInfo.Invoke, or Delegate.DynamicInvoke.

Important to notice here is that since setup for Expression Trees is expensive, if your method doesn’t get called very often, you may not have enough benefits from using Expression Trees. In case you know what types’ methods will be called, you may apply some kind of pre-compilation of methods on the application startup, in order to reuse the compiled delegates later.

Source code

You can try yourself to run the examples, the whole solution is available on github.

Stay tuned.

One thought on “Invoking methods dynamically in C#: Examples and benchmarks

  1. Pingback: dotnetomaniak.pl

Leave a Reply

Your email address will not be published. Required fields are marked *