通过" params"作为C#的输入

时间:2017-02-07 22:52:36

标签: c#

我有一个看起来像的函数:

FuncA(int num, object[] x)

这个函数将使用以这种方式编写的函数:

FuncB(string s, object x1)
FuncB(string s, object x1, object x2)
...

这样,函数B有很多这种形式的重载(实际上是32)并且是一个给定的函数(我无法访问它)。

我想在FuncA中调用FuncB,以便根据输入对象的长度调用正确的重载。

有一种聪明的方法吗?

由于

3 个答案:

答案 0 :(得分:3)

如果所有FuncB方法都属于同一个类,则可以使用Type.GetMethod重载,该重载接受包含每个参数的确切类型的Type[]参数。

另一方面,如果每个方法都是从其他地方提供的,您可以将它们存储在数组或字典中(即将“参数数量”映射到每个具体方法):

map[1] = (object[] x) => FuncB(x[0]);
map[2] = (object[] x) => FuncB(x[0], x[1]);

但是,我想知道你的设计是否正确,或许可以更好的方式实施。

答案 1 :(得分:0)

如果您不介意使用反射,那么您应该可以使用这种代码执行此操作:

int FuncA(int num, object[] x)
{
    if (x.Length == 0 || x.Length > 32) throw new ArgumentOutOfRangeException();
    IEnumerable<Type> types = new[] { typeof(string) }.Concat(x.Select(i => typeof(object)));
    MethodInfo info = typeof(FuncBClass).GetMethod("FuncB", types.ToArray());
    IEnumerable<object> parameters = new[] { "Some string" }.Concat(x);
    object result = info.Invoke(null /* ignored if the method is static */, parameters.ToArray());
    return (int)result;
}

基本上就是它的作用:

  • 获取IEnumerable<Type>目标方法重载的类型(FuncB有一个字符串,然后是n个对象x1 ... xn)
  • 获取代表要使用的目标重载的MethodInfo对象
  • 获取带有参数的IEnumerable<object>以传递给该方法重载,因此您的字符串然后是对象列表
  • 使用这些参数调用方法并投射其结果

备注

  • 我假设有一个FuncBClass类,其中包含您需要的所有方法
  • 我将null传递给Invoke方法,因为我认为这些方法是静态的。如果他们不是,您可能需要调整该行并创建其类的实例以传递给Invoke方法以使其正常工作

修改:这是一个示例,如果其中一个FuncB参数是out参数,则由OP建议。我假设参数是此处x1..xn数列表中的第一个参数,无论如何,对于每个可能的位置,一般的想法是相同的(或者如果out也是字符串)。< / p>

int FuncA(int num, object[] x)
{
    if (x.Length == 0 || x.Length > 32) throw new ArgumentOutOfRangeException();
    IEnumerable<Type> types = new[] { typeof(string) }.Concat(x.Select(i => typeof(object)));
    MethodInfo info = typeof(int).GetMethod("FuncB", types.ToArray());
    object[] parameters = new[] { "Some string", null /* the out parameter */ }.Concat(x.Skip(1)).ToArray();
    info.Invoke(null /* ignored if the method is static */, parameters);
    return (int)parameters[1]; // Get the out parameter value and cast it
}

答案 2 :(得分:0)

如果这是一个相当孤立的案例,并且你需要它是快速的,我可能会编写子弹并在长度上使用开关而不是使用反射(这将是更简洁的代码,但更慢)

所以

switch(num)
{
  case 1: return FuncB(x[0]); 
  case 2: return FuncB(x[0], x[1]); 
  etc
虽然丑陋,但速度相当快。

如果这是库中的常见模式,我可能会考虑使用一些代码生成来创建带适配器的程序集。或许某人已经创建了一个包装库。