Est-il possible d'exploser un tableau pour que ses éléments puissent être passés à une méthode avec le mot-clé params?
-
08-07-2019 - |
Question
Prenez ce code non compilant, par exemple:
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;
}
Cet exemple est une version quelque peu simplifiée du code de test que j'utilise. S'il vous plaît, je ne m'intéresse qu'aux solutions directement liées au mot-clé param. Je sais comment fonctionnent les listes et autres choses similaires.
Y a-t-il un moyen de " exploser " le tableau extraFolders afin que son contenu puisse être passé dans AppendFolders avec d'autres paramètres?
La solution
Une option consiste à transformer le params
paramètre en 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('\\')));
}
Si vous voulez quelque chose de plus typé, vous pouvez également créer un type d'union personnalisé avec des opérateurs de conversion implicites:
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};}
}
Dans les deux cas, cette compilation :
appendFolders("base", "v1", "module", new[]{"debug","bin"});
Autres conseils
Il suffit de le passer. Le paramètre folder est d'abord un tableau. les " params " les fonctionnalités sont un peu magiques pour le compilateur, mais ce n’est pas obligatoire.
AppendFolders(extraFolders);
Maintenant, dans ce cas particulier, vous devrez d’abord ajouter quelques éléments à ce tableau.
List<string> lstFolders = new List<string>(extraFolders);
lstFolder.Insert(0, callingModule);
lstFolder.Insert(0, version);
lstFolder.Insert(0, basefolder);
return AppendFolders(lstFolders.ToArray());
Je vais chicaner avec le terme & "; Réduire &" ;, puisqu'il semble que vous souhaitiez vraiment & "Développer &". Et je ne suis pas sûr de ce que vous entendez par solutions & "Ayant directement à faire avec le mot-clé params &"; et que & "vous n'êtes pas intéressé par les solutions de contournement &"; En fin de compte, vous devez soit passer un certain nombre de chaînes - que le compilateur va empaqueter comme par magie dans un tableau - ou directement un tableau de chaînes. Cela dit, ma solution (sans changer l’interface) ressemblerait à quelque chose comme:
return AppendFolders(new string[] { basefolder, version, callingModule }.Concat(extraFolders).ToArray());
Modifier:
Bien que vous ne puissiez pas ajouter d'opérateur via des méthodes d'extension, vous pouvez faire:
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();
}
Mais, si nous voulons aller aussi loin, nous pourrions également allonger la liste < T > pour gérer cela avec élégance:
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();
}
}
Une solution simple et rapide consisterait à créer une liste < string > à partir des éléments, puis passez-le (avec ToArray ()).
Notez que vous n'avez pas besoin de tester la barre oblique inverse. Path.Combine gère les bonnes choses plutôt bien .
Je pense que la réponse d’OregonGhost est probablement la façon dont vous voulez aller. Juste pour élaborer, il suggère de faire quelque chose comme ceci:
public string GetPath(string basefolder, string[] extraFolders)
{
string version = Versioner.GetBuildAndDotNetVersions();
string callingModule = StackCrawler.GetCallingModuleName();
List<string> parameters = new List<string>(extraFolders.Length + 3);
parameters.Add(basefolder);
parameters.Add(version);
parameters.Add(callingModule);
parameters.AddRange(extraFolders);
return AppendFolders(parameters.ToArray());
}
Et je ne veux pas dire cela comme une leçon sur la façon d'utiliser les listes, juste comme une petite clarification pour quiconque pourrait venir chercher la solution dans le futur.