繁体   English   中英

使用具有“params”参数的反射调用函数(MethodBase)

[英]Calling a function using reflection that has a “params” parameter (MethodBase)

我有两个函数的MethodBases:

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); 它返回:

未处理的异常:System.Reflection.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的签名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 });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM