3

In my project I have the following two methods which are used to call other methods with variable number and types of arguments:

 private static object InvokeMethod(MethodInfo method, MyTargetClass target, object[] initialArgs, object[] additionalArgs)
{
    object result = null;
    var methodParams = method.GetParameters();

    if (methodParams.Length == 0)
    {
        result = method.Invoke(target, null);
    }
    else
    {
        var args =  CollectArguments(method, initialArgs, paramArgs);
        // collect arguments with default values for missing ones and invoke the method
        result = method.Invoke(target,args);
    }

    return result;
}

private static object[] CollectArguments(MethodInfo method, object[] initialArgs, object[] paramArgs)
{
    List<object> allArgs = new List<object>();
    allArgs.AddRange(initialArgs);

    // append all param style args
    if (paramArgs != null)
        allArgs.AddRange(paramArgs);

    // do we have enough arguments?
    int missing = method.GetParameters().Length - allArgs.Count;

    if (missing < 0)
        throw new InvalidOperationException(string.Format("Too many arguments passed to the method {0}", method.Name));

    for (int i = 0; i < missing; i++)
    {
        // all parameters after mandatory should be with optional default values, so pass them
        allArgs.Add(Type.Missing);
    }

    return allArgs.ToArray();
}

My InvokeMethod is called often, so I would like to optimize it. I already am caching MethodInfo references. All the methods to call have a custom attribute and I collect those methods in a dictionary upon application startup. I managed to cache lambda expressions for constructors of MyTargetClass derived classes and now I would like also to cache lambda expressions for method calls.

I have found some examples how to create lambda expressions for Expression.Call, but the problem is that I don't know how to deal with variable arguments, which include also default values (that's why I am adding Type.Missing) and also there might be ref arguments.

There are some additional rules for the methods I want to invoke (omitted for brevity), but basically methods might look like this:

MyMethod1(int a, long b = 2)
MyMethod2(ref long a, ref long b, string something)

I always know those special cases with ref arguments, so after method.Invoke I collect ref variables back:

a = (long)allArgs[0];
b = (long)allArgs[1];

where a and b are passed by ref from outside.

How do I achieve the same functionality using Expression.Call? How do I pass variable count of arguments to it and how do I get ref values?

JustAMartin
  • 13,165
  • 18
  • 99
  • 183

0 Answers0