简体   繁体   中英

Calling a function with unkown amout of parameter in c#

I have a function

public static SomeFunction(string a, string b = "", string c = "", string d = "")
{
return a + b + c + d;
}

I have an unknow amount of strings (1-4) which are stored in a list (can also be stored differently).

How do I call SomeFunction() with the strings now even if I don't actually know how many items will be in the list?

The function is given and can't be changed.

Well, the easy thing is to just wrap it:

string MyFunctionEx(IList<string> values) {
   switch (values.Length) {
       case 1:
          return MyFunction(values[0]);
       case 2:
          return MyFunction(values[0], values[1]);
       case 3:
          return MyFunction(values[0], values[1], values[2]);
       case 4:
          return MyFunction(values[0], values[1], values[3], values[4]);
       break:
          throw new InvalidOperationException();
}

Presumably you were looking for something more general purpose than that? Well, in that case, I'd normally say dynamic would be the way to go - unfortunately, since this is a static method, you don't have that luxury and will have to use Reflection. One thing to note is that the optional parameters still need to be passed, but should be Type.Missing :

object[] parameters = new object[4];
for (var i = 0; i < parameters.Length; i++) {
     parameters[i] = i < myList.Count ? myList[i] : Type.Missing;
}
MethodInfo mi = typeof(SomeClass).GetMethod(nameof(SomeClass.SomeFunction));
string result = (string)mi.Invoke(null, parameters);

Your function would be better served if it were something like this:

public static string SomeFunction(IEnumerable<string> values)
{
    return string.Concat(values);
}

Which could then be passed a List<string> , string[] , or other enumerable of string and concatenate it, although you really aren't doing much by adding a layer of abstraction to string.Concat , so I'd drop the function entirely and just use the built-in function in this case.

Edit

If it is not possible to modify the method as you say, then there is another alternative, you could do something like this:

public static string SomeFunctionInvoker(IEnumerable<string> values)
{
    var listStr = values.ToArray();    //<-- Requires System.Linq

    if (listStr.Length > 4)
        throw new ArgumentException("Too many arguments provided");

    if (listStr.Length == 0)
        throw new ArgumentException("Not enough arguments provided");

    string[] strArray4 = new string[4];

    Array.Copy(listStr, strArray4, listStr.Length);

    return SomeFunction(strArray4[0], strArray4[1], strArray4[2], strArray4[3]);
}

Basically what is happening here is that you are passing in an IEnumerable<string> to the invoker function that makes sure that the number of arguments fit in the SomeFunction argument list. It then creates an array with the maximum number of arguments, copies the original array into it, and then passes all the arguments to SomeFunction .

This only works if SomeFunction 's default parameters use string.Empty or null for the default value. If it had some other default value, then the only way to get the default values and pass them in without knowing at compile time is to use reflection .

void SomeFunction(params string[] val) lets you pass an arbitrary number of string parameters, which are seen as an array from the inside of the function. If you want to pass anything at all, you can use object[] after the params keyword.

What about this

    List<string> list = new List<string> { "aaa", "bbb" };

    switch(list.Count){
        case 1: SomeFunction(list[0]);break;
        case 2: SomeFunction(list[0], list[1]);break;
        case 3: SomeFunction(list[0], list[1], list[2]);break;
        case 4: SomeFunction(list[0], list[1], list[2], list[3]);break;
        default: throw new ArgumentException("List length out of range");
    }

Assuming by the + you mean join and not add them as numbers I would recommend something quick and easy like:

public string joinMyStrings(List<string> values) 
{
     return string.Join("", values);  // add any dividers if wanted
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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