È possibile esplodere un array in modo che i suoi elementi possano essere passati a un metodo con la parola chiave params?

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

Domanda

Prendi questo codice non compilante per esempio:

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;
}

Questo esempio è una versione in qualche modo semplificata del codice di test che sto usando. Per favore, sono interessato solo alle soluzioni che hanno a che fare direttamente con la parola chiave param. So come funzionano le liste e altre cose simili.

C'è un modo per " esplodere " l'array extraFolders in modo che il suo contenuto possa essere passato in AppendFolders insieme ad altri parametri?

È stato utile?

Soluzione

Un'opzione è di rendere il params parametro 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('\\')));
 }

Se vuoi qualcosa di più fortemente tipizzato, un'altra opzione è quella di creare un tipo di unione personalizzato con operatori di conversione impliciti:

  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 entrambi i casi, questo verrà compilato :

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

Altri suggerimenti

Passalo e basta. Il parametro cartelle è innanzitutto un array. il " params " la funzionalità è un po 'magica del compilatore, ma non è richiesta.

AppendFolders(extraFolders);

Ora, in questa particolare istanza, prima devi aggiungere alcune cose a quell'array.

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

Scontrerò con il termine " collapse " ;, poiché sembra che tu voglia davvero " espandere " ;. E non sono sicuro di cosa intendi con soluzioni & Quot; avendo a che fare direttamente con la parola chiave params & Quot; e quel " non ti interessano soluzioni alternative " ;. Alla fine, devi passare un certo numero di stringhe - che il compilatore impacchetterà magicamente in un array - o direttamente un array di stringhe. Detto questo, la mia soluzione (senza cambiare l'interfaccia) sarebbe simile a:

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

Modifica:

Sebbene non sia possibile aggiungere un operatore tramite metodi di estensione, è possibile eseguire:

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

Ma se andiamo così lontano - potrebbe anche estendere la Lista < T > per gestirlo elegantemente:

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

Una soluzione rapida e sporca sarebbe quella di costruire un Elenco < string > dagli elementi e quindi passalo (con ToArray ()).

Nota che non è necessario testare la barra rovesciata. Path.Combine gestisce le cose sporche piuttosto bene .

Penso che la risposta di OregonGhost sia probabilmente il modo in cui vuoi andare. Solo per approfondire, sta suggerendo di fare qualcosa del genere:

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

E non intendo questo come una lezione su come usare gli Elenchi, ma solo un piccolo chiarimento per chiunque possa venire a cercare la soluzione in futuro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top