我有两个函数的MethodBase:
public static int Add(params int[] parameters) { /* ... */ }
public static int Add(int a, int b) { /* ... */ }
我有一个函数,它通过我创建的一个类调用MethodBases:
MethodBase Method;
object Target;
public object call(params object[] input)
{
return Method.Invoke(Target, input);
}
现在,如果我AddTwoMethod.call(5, 4);
,它可以正常工作。
但是,如果我使用AddMethod.call(5, 4);
,它会返回:
未处理的异常:系统。反射TargetParameterCountException:参数与签名不匹配
有没有什么方法可以让这两个调用都能正常工作,而不需要手动将参数放入params int[]
的数组中?
您可以修改call
方法来检测params参数,并将其余输入转换为新数组。通过这种方式,您的方法的行为与C#应用于方法调用的逻辑几乎相同。
我为你巧妙地构建了一些东西(请注意,我测试这种方法的方式非常有限,所以可能仍然存在错误):
public object call(params object[] input)
{
ParameterInfo[] parameters = Method.GetParameters();
bool hasParams = false;
if (parameters.Length > 0)
hasParams = parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0;
if (hasParams)
{
int lastParamPosition = parameters.Length - 1;
object[] realParams = new object[parameters.Length];
for (int i = 0; i < lastParamPosition; i++)
realParams[i] = input[i];
Type paramsType = parameters[lastParamPosition].ParameterType.GetElementType();
Array extra = Array.CreateInstance(paramsType, input.Length - lastParamPosition);
for (int i = 0; i < extra.Length; i++)
extra.SetValue(input[i + lastParamPosition], i);
realParams[lastParamPosition] = extra;
input = realParams;
}
return Method.Invoke(Target, input);
}
请注意,我测试这个方法的方式非常有限,所以可能仍然存在错误。
假设我们有以下示例类:
public class Test
{
public static int Add(int i1, int i2)
{
return i1 + i2;
}
public static int Add(params int[] ints)
{
int sum = 0;
foreach (int i in ints)
sum += i;
return sum;
}
}
要为静态Add
方法的每个重载获取MethodInfo
对象,您应该执行以下操作:
MethodInfo Add2Ints = typeof(Test).GetMethod("Add", new Type[] { typeof(int), typeof(int) });
MethodInfo AddParamsInts = typeof(Test).GetMethod("Add", new Type[] { typeof(int[]) });
为了调用这两个方法中的任何一个,请用您正在调用的特定重载所期望的确切类型来传递参数:
Add2Ints.Invoke(null, new object[] { 1, 2 });
AddParamsInts.Invoke(null, new object[] { new int[] { 1, 2 } });
请注意,以下操作不起作用:
AddParamsInts.Invoke(null, new object[] { 1, 2 });
因为AddParmsInt
的签名实际上是(int[])
,尽管编译器出于礼貌,允许在后台调用(int, int)
这样的方法,但实际发生的是,在调用站点为您转换为等效的(int[])
调用。通过反射,您没有编译器的"帮助",因此需要传递由方法签名定义的精确参数类型。
综上所述,您的call
方法应该如下所示:
public object call(params object[] input)
{
return AddParamsInts.Invoke(null /*static*/, new object[] { input.Cast<int>().ToArray() });
}
请注意,不能将object[]
数组直接强制转换为int[]
数组:int[] ints = (int[])input
。不允许将引用类型的数组强制转换为值类型的数组。
同样需要注意的是,Add
方法定义的重载是无用的,因为它们重叠。考虑只使用params
重载,或者,如果您想保证至少需要两个参数来评估添加,请按以下方式重载它们:
public int Add(int i1, int i2) { }
public int Add(int i1, int i2, params int[] args) { }
您应该将参数包装在一个数组中,但编译器会感到困惑,因此您需要帮助它:
例如:
AddMethod.call((object) new int[] {5, 4 });