2008-10-10 3 views
5

Prenez ce code non-compilation par exemple:Est-il possible d'exploser un tableau afin que ses éléments puissent être passés à une méthode avec le mot-clé params?

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 je utilise. S'il vous plaît, je suis seulement intéressé par les solutions ayant directement à faire avec le mot-clé param. Je sais comment fonctionnent les listes et d'autres choses semblables.

Existe-t-il un moyen d '«exploser» la matrice extraFolders afin que son contenu puisse être transmis à AppendFolders avec d'autres paramètres?

+0

Pour être sûr de bien comprendre, vous voulez que le tableau extraFolders soit envoyé dans la méthode AppendFolders en tant que AppendFolders (extraFolders [0], extraFolders [1], ... etc etc)? Question intéressante, je serais curieux si c'est possible, même si je ne vois pas comment .... – BFree

+0

C'est exactement ce que je veux. –

+0

Votre clarification ajoute juste plus de confusion. Est-ce que les éléments supplémentaires qui sont passés sont une partie importante de ceci ou pas? Sinon, la première moitié de ma réponse est ce que vous voulez. Si c'est le cas, c'est un cas très particulier, traité par la seconde moitié de ma réponse. –

Répondre

1

Une option est de rendre le paramètre params un 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 fortement typé, une autre option est de créer un type d'union douanière avec les opérateurs de conversion implicite:

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, ce sera compilation:

appendFolders("base", "v1", "module", new[]{"debug","bin"}); 
1

Une solution rapide et sale serait de construire une liste < chaîne > à partir des éléments, puis passer cela (avec ToArray()).

Notez que vous n'avez pas besoin de tester le backslash. Path.Combine gère the dirty things rather fine.

+0

Dans certains cas, le backslash ne sera pas géré correctement. Je me suis retrouvé avec une double barre oblique inverse dans le passé. ex. Blah \\ Blah –

+0

Ensuite, il pourrait s'agir d'un bug que vous pouvez déposer sur http://connect.microsoft.com - et si vous voulez rester avec le backslash, au moins utiliser Path.DirectorySeparatorChar au lieu d'un codé en dur antislash. – OregonGhost

+0

* Path.Combine * rencontre des problèmes si le second chemin commence par une barre oblique inverse. – brgerner

7

Il suffit de le passer. Le paramètre folders est un tableau en premier. la fonctionnalité "params" est un peu de magie du compilateur, mais ce n'est pas obligatoire.

AppendFolders(extraFolders); 

Maintenant, il particulat cette instance, vous devrez ajouter certaines choses à ce tableau, tout d'abord.

List<string> lstFolders = new List<string>(extraFolders); 
lstFolder.Insert(0, callingModule); 
lstFolder.Insert(0, version); 
lstFolder.Insert(0, basefolder); 
return AppendFolders(lstFolders.ToArray()); 
+0

Je suppose que le point était que vous ne pouvez pas ajouter des choses à un tableau :) – OregonGhost

1

Je pense que la réponse de OregonGhost est probablement la façon dont vous voulez aller. Juste d'en dire plus, 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 que comme une leçon sur la façon d'utiliser les listes, comme une petite précision pour tous ceux qui peuvent venir chercher le long de la solution à l'avenir.

2

Je vais ergoter avec le terme "effondrement", car il semble que vous voulez vraiment "développer". Et je ne suis pas sûr de ce que vous entendez par des solutions "ayant directement à faire avec le mot-clé params" et que "vous n'êtes pas intéressé par les solutions de contournement". À la fin, vous devez passer un certain nombre de chaînes - que le compilateur va magiquement empaqueter dans un tableau - ou un tableau de chaînes directement.Cela étant dit, ma solution (sans changer l'interface) serait quelque chose comme:

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

Edit:

Alors que vous ne pouvez pas ajouter un 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 allons aller aussi loin - étendre pourrait tout aussi bien Liste <T> pour gérer cette élégante:

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(); 
    } 
} 
+0

Ceci est vraiment proche de ce que je veux. Élégant et similaire à ce qu'un compilateur pourrait faire. –

+0

Tout aussi cool serait: nouvelle chaîne [] {baseFolder, callingModuleName, version} + extraFolders –

Questions connexes