Est-il possible d'exploser un tableau pour que ses éléments puissent être passés à une méthode avec le mot-clé params?

StackOverflow https://stackoverflow.com/questions/192715

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?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top