Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to explode an array so that its elements can be passed to a method with the params keyword?

Take this non-compiling code for instance:

public string GetPath(string basefolder, string[] extraFolders)
{
    string version = Versioner.GetBuildAndDotNetVersions();
    string callingModule = StackCrawler.GetCallingModuleName();
    return AppendFolders(basefolder, version, callingModule, extraFolders);
}
private string AppendFolders(params string[] folders)
{
    string outstring = folders[0];
    for (int i = 1; i < folders.Length; i++)
    {
        string fixedPath = folders[i][0] == '\\' ? folders[i].Substring(1) : folders[i];
        Path.Combine(outstring, fixedPath);
    }
    return outstring;
}

This example is a somewhat simplified version of testing code I am using. Please, I am only interested in solutions having directly to do with the param keyword. I know how lists and other similar things work.

Is there a way to "explode" the extraFolders array so that it's contents can be passed into AppendFolders along with other parameters?

like image 792
Rick Minerich Avatar asked Oct 10 '08 19:10

Rick Minerich


People also ask

What is the purpose of params keyword?

By using the params keyword, you can specify a method parameter that takes a variable number of arguments. The parameter type must be a single-dimensional array. No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration.

What is the params keyword in C#?

Params is an important keyword in C#. It is used as a parameter which can take the variable number of arguments. Important Point About Params Keyword : It is useful when programmer don't have any prior knowledge about the number of parameters to be used.

How many parameters can a method have C#?

Parameters and Arguments They are specified after the method name, inside the parentheses. You can add as many parameters as you want, just separate them with a comma.

What is parameter array in C#?

C# Parameter array is declared with the params modifier. Parameter type must be declared as an array. Must be of a single-dimensional Array type. Single params array per method is allowed. Must be the last argument in the method's parameter list.


3 Answers

Just pass it. The folders parameter is an array first. the "params" functionality is a little bit of compiler magic, but it's not required.

AppendFolders(extraFolders);

Now, it this particulat instance, you'll have to add some things to that array, first.

List<string> lstFolders = new List<string>(extraFolders);
lstFolder.Insert(0, callingModule);
lstFolder.Insert(0, version);
lstFolder.Insert(0, basefolder);
return AppendFolders(lstFolders.ToArray());
like image 69
James Curran Avatar answered Sep 24 '22 21:09

James Curran


I'll quibble with the term "collapse", since it seems you really want to "expand". And I'm not sure what you mean by solutions "having directly to do with params keyword" and that "you're not interested in workarounds". In the end, you either have to pass a number of strings - which the compiler will magically package into an array - or an array of strings directly. That being said, my solution (without changing the interface) would go something like:

return AppendFolders(new string[] { basefolder, version, callingModule }.Concat(extraFolders).ToArray());

Edit:

While you can't add an operator via extension methods, you could do:

return AppendFolders(new string[] { baseFolder, callingModuleName, version }.Concat(extraFolders));

public static T[] Concat<T>(this T[] a, T[] b) {
   return ((IEnumerable<T>)a).Concat(b).ToArray();
}

But, if we're going to go that far - might as well just extend List<T> to handle this elegantly:

return AppendFolders(new Params<string>() { baseFolder, callingModuleName, version, extraFolders });

class Params<T> : List<T> {
    public void Add(IEnumerable<T> collection) {
       base.AddRange(collection);
    }

    public static implicit operator T[](Params<T> a) {
       return a.ToArray();
    }
}
like image 24
Mark Brackett Avatar answered Sep 21 '22 21:09

Mark Brackett


One option is to make the params parameter an object[]:

static string appendFolders(params object[] folders)
 { return (string) folders.Aggregate("",(output, f) => 
                       Path.Combine( (string)output
                                    ,(f is string[]) 
                                      ? appendFolders((object[])f)
                                      : ((string)f).TrimStart('\\')));
 }

If you want something more strongly-typed, another option is to create a custom union type with implicit conversion operators:

  static string appendFolders(params StringOrArray[] folders)
     { return folders.SelectMany(x=>x.AsEnumerable())
                     .Aggregate("",
                       (output, f)=>Path.Combine(output,f.TrimStart('\\')));
     }

   class StringOrArray
     { string[] array;

       public IEnumerable<string> AsEnumerable()
        { return soa.array;}

       public static implicit operator StringOrArray(string   s)   
        { return new StringOrArray{array=new[]{s}};}

       public static implicit operator StringOrArray(string[] s)  
        { return new StringOrArray{array=s};}
     }

In either case, this will compile:

appendFolders("base", "v1", "module", new[]{"debug","bin"});
like image 33
Mark Cidade Avatar answered Sep 20 '22 21:09

Mark Cidade