将MethodInfo.Invoke转换为Expression.Call

时间:2013-02-13 13:27:43

标签: c# lambda invoke precompiled

在我的项目中,我有以下两种方法,用于调用具有可变数量和参数类型的其他方法:

 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();
}

我经常调用我的InvokeMethod,所以我想优化它。我已经在缓存MethodInfo引用了。所有要调用的方法都有一个自定义属性,我在应用程序启动时在字典中收集这些方法。我设法为MyTargetClass派生类的构造函数缓存lambda表达式,现在我还要为方法调用缓存lambda表达式。

我找到了一些如何为Expression.Call创建lambda表达式的例子,但问题是我不知道如何处理变量参数,其中也包含默认值(这就是我添加Type.Missing的原因)并且可能还有ref参数。

我想要调用的方法有一些额外的规则(为简洁起见省略),但基本上方法可能如下所示:

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

我总是知道那些带有ref参数的特殊情况,所以在method.Invoke之后我收集了ref变量:

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

其中a和b通过ref从外部传递。

如何使用Expression.Call实现相同的功能?如何向其传递变量的参数计数以及如何获得ref值?

0 个答案:

没有答案