在我的项目中,我有以下两种方法,用于调用具有可变数量和参数类型的其他方法:
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值?